Skip to content

Commit

Permalink
✨: feat SQS Message Produce 실패에 대한 처리 구현 #70
Browse files Browse the repository at this point in the history
  • Loading branch information
PgmJun authored Sep 21, 2024
2 parents f57306c + c939fc9 commit 4a2bb29
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 45 deletions.
1 change: 1 addition & 0 deletions lionheart-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ dependencies {

// sqs
implementation "org.springframework.cloud:spring-cloud-aws-messaging:2.2.6.RELEASE"
implementation 'org.springframework.retry:spring-retry:1.3.4'


// // s3
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.chiwawa.lionheart.api.config.sqs;

import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class SqsRetryListener implements RetryListener {
@Override
public <T, E extends Throwable> boolean open(RetryContext retryContext, RetryCallback<T, E> retryCallback) {
log.info("SqsRetryListener Opened");
return true;
}

@Override
public <T, E extends Throwable> void close(RetryContext retryContext, RetryCallback<T, E> retryCallback,
Throwable throwable) {
log.info("SqsRetryListener Closed");
}

@Override
public <T, E extends Throwable> void onError(RetryContext retryContext, RetryCallback<T, E> retryCallback,
Throwable throwable) {
int retryCount = retryContext.getRetryCount();
log.info("Sqs Message Produce 과정에서 에러가 발생하였습니다. :: (RetryCount: {})", retryCount, throwable);
}
}
Original file line number Diff line number Diff line change
@@ -1,57 +1,73 @@
package com.chiwawa.lionheart.api.config.sqs.producer;

import java.util.Map;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import static com.chiwawa.lionheart.common.exception.ErrorCode.SQS_EXCEPTION;

import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.model.AmazonSQSException;
import com.amazonaws.services.sqs.model.MessageAttributeValue;
import com.amazonaws.services.sqs.model.SendMessageRequest;
import com.chiwawa.lionheart.common.constant.MessageType;
import com.chiwawa.lionheart.common.dto.sqs.MessageDto;
import com.chiwawa.lionheart.common.exception.model.InternalServerException;
import com.chiwawa.lionheart.common.util.MessageUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Map;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class SqsProducer {

@Value("${cloud.aws.sqs.notification.url}")
private String notificationUrl;

private static final String messageGroupId = "sqs";
private final ObjectMapper objectMapper;
private final AmazonSQS amazonSqs;
private static final String SQS_QUEUE_REQUEST_LOG_MESSAGE = "====> [SQS Queue Request] : %s ";

public SqsProducer(ObjectMapper objectMapper, AmazonSQS amazonSqs) {
this.objectMapper = objectMapper;
this.amazonSqs = amazonSqs;
}

public void produce(MessageDto dto) {
try {
SendMessageRequest sendMessageRequest = new SendMessageRequest(notificationUrl,
objectMapper.writeValueAsString(dto))
.withMessageGroupId(messageGroupId)
.withMessageDeduplicationId(UUID.randomUUID().toString())
.withMessageAttributes(createMessageAttributes(dto.getType()));
amazonSqs.sendMessage(sendMessageRequest);
log.info(MessageUtils.generate(SQS_QUEUE_REQUEST_LOG_MESSAGE, dto));
} catch (JsonProcessingException exception) {
log.error(exception.getMessage(), exception);
}
}

private Map<String, MessageAttributeValue> createMessageAttributes(String type) {
final String dataType = "String";
return Map.of(MessageType.MESSAGE_TYPE_HEADER, new MessageAttributeValue()
.withDataType(dataType)
.withStringValue(type));
}
@Value("${cloud.aws.sqs.notification.url}")
private String notificationUrl;

private static final String messageGroupId = "sqs";
private final ObjectMapper objectMapper;
private final AmazonSQS amazonSqs;
private static final String SQS_QUEUE_REQUEST_LOG_MESSAGE = "====> [SQS Queue Request] : %s ";

public SqsProducer(ObjectMapper objectMapper, AmazonSQS amazonSqs) {
this.objectMapper = objectMapper;
this.amazonSqs = amazonSqs;
}

@Retryable(
maxAttempts = 3,
backoff = @Backoff(delay = 1000),
include = {AmazonSQSException.class},
listeners = {"SqsRetryListener"})
public void produce(MessageDto dto) {
try {
SendMessageRequest sendMessageRequest = new SendMessageRequest(notificationUrl,
objectMapper.writeValueAsString(dto))
.withMessageGroupId(messageGroupId)
.withMessageDeduplicationId(UUID.randomUUID().toString())
.withMessageAttributes(createMessageAttributes(dto.getType()));
amazonSqs.sendMessage(sendMessageRequest);
log.info(MessageUtils.generate(SQS_QUEUE_REQUEST_LOG_MESSAGE, dto));
} catch (JsonProcessingException exception) {
throw new AmazonSQSException("Message sending failed by json processing.");
}
}

@Recover
private void recoverListener(AmazonSQSException exception, MessageDto dto) {
throw new InternalServerException(
String.format("SQS로 메시지를 Produce 하는 과정에서 에러가 발생하며 메시지 발행에 실패하였습니다. :: Message -> %s", dto.toString())
, SQS_EXCEPTION);
}

private Map<String, MessageAttributeValue> createMessageAttributes(String type) {
final String dataType = "String";
return Map.of(MessageType.MESSAGE_TYPE_HEADER, new MessageAttributeValue()
.withDataType(dataType)
.withStringValue(type));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public enum ErrorCode {

// Internal Server Exception
INTERNAL_SERVER_EXCEPTION("I001", "서버 내부에서 에러가 발생하였습니다."),
SQS_EXCEPTION("I002", "SQS 연동 과정에서 서버 내부 에러가 발생하였습니다."),

// Bad Gateway Exception
BAD_GATEWAY_EXCEPTION("B001", "외부 연동 중 에러가 발생하였습니다.");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
package com.chiwawa.lionheart.domain.domain.common;

import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;

import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;

import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import com.fasterxml.jackson.annotation.JsonFormat;

import lombok.Getter;

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
Expand Down

0 comments on commit 4a2bb29

Please sign in to comment.