diff --git a/backend/src/main/java/com/twtw/backend/config/rabbitmq/RabbitMQConfig.java b/backend/src/main/java/com/twtw/backend/config/rabbitmq/RabbitMQConfig.java index 4704bd5e..9ffd0539 100644 --- a/backend/src/main/java/com/twtw/backend/config/rabbitmq/RabbitMQConfig.java +++ b/backend/src/main/java/com/twtw/backend/config/rabbitmq/RabbitMQConfig.java @@ -3,13 +3,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.twtw.backend.global.constant.RabbitMQConstant; import com.twtw.backend.global.properties.RabbitMQProperties; - import lombok.RequiredArgsConstructor; - -import org.springframework.amqp.core.Binding; -import org.springframework.amqp.core.BindingBuilder; -import org.springframework.amqp.core.Queue; -import org.springframework.amqp.core.TopicExchange; +import org.springframework.amqp.core.*; import org.springframework.amqp.rabbit.annotation.EnableRabbit; import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory; @@ -29,7 +24,10 @@ public class RabbitMQConfig { @Bean public Queue locationQueue() { - return new Queue(RabbitMQConstant.LOCATION_QUEUE.getName(), true); + return QueueBuilder.durable(RabbitMQConstant.LOCATION_QUEUE.getName()) + .withArgument("x-dead-letter-exchange", RabbitMQConstant.DEAD_LETTER_EXCHANGE.getName()) + .withArgument("x-dead-letter-routing-key", RabbitMQConstant.DEAD_LETTER_ROUTING_KEY.getName()) + .build(); } @Bean @@ -46,7 +44,10 @@ public Binding locationBinding() { @Bean public Queue notificationQueue() { - return new Queue(RabbitMQConstant.NOTIFICATION_QUEUE.getName(), true); + return QueueBuilder.durable(RabbitMQConstant.NOTIFICATION_QUEUE.getName()) + .withArgument("x-dead-letter-exchange", RabbitMQConstant.DEAD_LETTER_EXCHANGE.getName()) + .withArgument("x-dead-letter-routing-key", RabbitMQConstant.DEAD_LETTER_ROUTING_KEY.getName()) + .build(); } @Bean @@ -61,6 +62,23 @@ public Binding notificationBinding() { .with(RabbitMQConstant.NOTIFICATION_ROUTING_KEY.getName()); } + @Bean + public Queue deadLetterQueue() { + return QueueBuilder.durable(RabbitMQConstant.DEAD_LETTER_QUEUE.getName()).build(); + } + + @Bean + public TopicExchange deadLetterExchange() { + return new TopicExchange(RabbitMQConstant.DEAD_LETTER_EXCHANGE.getName()); + } + + @Bean + public Binding deadLetterBinding() { + return BindingBuilder.bind(deadLetterQueue()) + .to(deadLetterExchange()) + .with(RabbitMQConstant.DEAD_LETTER_ROUTING_KEY.getName()); + } + @Bean public ConnectionFactory connectionFactory() { CachingConnectionFactory factory = new CachingConnectionFactory(); @@ -94,6 +112,11 @@ public RabbitAdmin rabbitAdmin(final ConnectionFactory connectionFactory) { rabbitAdmin.declareQueue(notificationQueue()); rabbitAdmin.declareExchange(notificationTopicExchange()); rabbitAdmin.declareBinding(notificationBinding()); + + rabbitAdmin.declareQueue(deadLetterQueue()); + rabbitAdmin.declareExchange(deadLetterExchange()); + rabbitAdmin.declareBinding(deadLetterBinding()); + return rabbitAdmin; } } diff --git a/backend/src/main/java/com/twtw/backend/domain/deadletter/DeadLetterConsumer.java b/backend/src/main/java/com/twtw/backend/domain/deadletter/DeadLetterConsumer.java new file mode 100644 index 00000000..5c64a875 --- /dev/null +++ b/backend/src/main/java/com/twtw/backend/domain/deadletter/DeadLetterConsumer.java @@ -0,0 +1,32 @@ +package com.twtw.backend.domain.deadletter; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; + +@Slf4j +@Component +public class DeadLetterConsumer { + + private final WebClient webClient; + private final String slackUrl; + + public DeadLetterConsumer(@Value("${slack.url}") final String slackUrl) { + this.webClient = WebClient.create("https://hooks.slack.com/services/"); + this.slackUrl = slackUrl; + } + + @RabbitListener(queues = "deadletter.queue") + public void handleDeadLetterMessage(final String message) { + log.error("Dead letter received: {}", message); + webClient.post() + .uri(slackUrl) + .bodyValue("{\"text\": \"Dead letter received: " + message + "\"}") + .retrieve() + .bodyToMono(String.class) + .doOnSuccess(s -> log.info("Slack message sent: {}", s)) + .subscribe(); + } +} diff --git a/backend/src/main/java/com/twtw/backend/domain/notification/messagequeue/FcmConsumer.java b/backend/src/main/java/com/twtw/backend/domain/notification/messagequeue/FcmConsumer.java index 13301f5b..5674b15a 100644 --- a/backend/src/main/java/com/twtw/backend/domain/notification/messagequeue/FcmConsumer.java +++ b/backend/src/main/java/com/twtw/backend/domain/notification/messagequeue/FcmConsumer.java @@ -19,11 +19,7 @@ public FcmConsumer(FirebaseMessaging firebaseMessaging) { } @RabbitListener(queues = "notification.queue") - public void sendNotification(final NotificationRequest request) { - try { - firebaseMessaging.send(request.toMessage()); - } catch (FirebaseMessagingException e) { - log.error(e.getMessage()); - } + public void sendNotification(final NotificationRequest request) throws FirebaseMessagingException { + firebaseMessaging.send(request.toMessage()); } } diff --git a/backend/src/main/java/com/twtw/backend/global/constant/RabbitMQConstant.java b/backend/src/main/java/com/twtw/backend/global/constant/RabbitMQConstant.java index 6c9dbc4c..a072e6a3 100644 --- a/backend/src/main/java/com/twtw/backend/global/constant/RabbitMQConstant.java +++ b/backend/src/main/java/com/twtw/backend/global/constant/RabbitMQConstant.java @@ -12,7 +12,10 @@ public enum RabbitMQConstant { LOCATION_ROUTING_KEY_PREFIX("location."), NOTIFICATION_QUEUE("notification.queue"), NOTIFICATION_EXCHANGE("notification"), - NOTIFICATION_ROUTING_KEY("notification"); + NOTIFICATION_ROUTING_KEY("notification"), + DEAD_LETTER_QUEUE("deadletter.queue"), + DEAD_LETTER_EXCHANGE("deadletter"), + DEAD_LETTER_ROUTING_KEY("deadletter"); private final String name; } diff --git a/backend/src/main/resources/application-prod.yml b/backend/src/main/resources/application-prod.yml index c24918cb..dc6ecf6e 100644 --- a/backend/src/main/resources/application-prod.yml +++ b/backend/src/main/resources/application-prod.yml @@ -83,3 +83,5 @@ tmap: url: ${TMAP_URL} firebase: location: ${FIREBASE_LOCATION} +slack: + url: ${SLACK_URL} \ No newline at end of file