From a67aa675553275b66b8cb04120fd06bd5c2f05f1 Mon Sep 17 00:00:00 2001 From: Dltmd202 Date: Fri, 2 Aug 2024 13:08:19 +0900 Subject: [PATCH 1/3] =?UTF-8?q?chore:=20rmq=20=EC=9D=98=EC=A1=B4=EC=84=B1?= =?UTF-8?q?=20=EC=A3=BC=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/build.gradle.kts | 3 +++ notification/build.gradle.kts | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/infra/build.gradle.kts b/infra/build.gradle.kts index ff07679a..8abc9bf5 100644 --- a/infra/build.gradle.kts +++ b/infra/build.gradle.kts @@ -31,6 +31,9 @@ dependencies { implementation("com.querydsl:querydsl-apt:5.0.0:jakarta") implementation("jakarta.persistence:jakarta.persistence-api") implementation("jakarta.annotation:jakarta.annotation-api") + //implementation("org.springframework.boot:spring-boot-starter-amqp") + + //testImplementation("org.springframework.amqp:spring-rabbit-test") kapt("com.querydsl:querydsl-apt:5.0.0:jakarta") kapt("org.springframework.boot:spring-boot-configuration-processor") diff --git a/notification/build.gradle.kts b/notification/build.gradle.kts index 01b91149..f000cae8 100644 --- a/notification/build.gradle.kts +++ b/notification/build.gradle.kts @@ -15,7 +15,6 @@ dependencies { implementation(project(":domain")) implementation(project(":infra")) implementation("org.springframework.boot:spring-boot-starter-actuator") - implementation("org.springframework.boot:spring-boot-starter-web") testImplementation(kotlin("test")) } From 033811af888f9fe40a27a70cf85ce7cae31a8dee Mon Sep 17 00:00:00 2001 From: Dltmd202 Date: Fri, 2 Aug 2024 13:16:05 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20rmq=20=ED=95=B8=EB=93=A4=EB=A7=81?= =?UTF-8?q?=20=EB=AA=A8=EB=93=88=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NotificationRMQEventPublisherConfig.kt | 32 +++++++++++++ .../config/NotificationRMQProducerConfig.kt | 27 +++++++++++ .../serivce/NotificationRMQEventService.kt | 14 ++++++ .../rmq/serivce/RMQEventPublisher.kt | 37 +++++++++++++++ .../amaker/infra/rmq/config/RMQConfig.kt | 47 +++++++++++++++++++ 5 files changed, 157 insertions(+) create mode 100644 infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/config/NotificationRMQEventPublisherConfig.kt create mode 100644 infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/config/NotificationRMQProducerConfig.kt create mode 100644 infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/serivce/NotificationRMQEventService.kt create mode 100644 infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/serivce/RMQEventPublisher.kt create mode 100644 infra/src/main/kotlin/com/backgu/amaker/infra/rmq/config/RMQConfig.kt diff --git a/infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/config/NotificationRMQEventPublisherConfig.kt b/infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/config/NotificationRMQEventPublisherConfig.kt new file mode 100644 index 00000000..3dc9487b --- /dev/null +++ b/infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/config/NotificationRMQEventPublisherConfig.kt @@ -0,0 +1,32 @@ +package com.backgu.amaker.infra.notification.rmq.config + +import com.backgu.amaker.infra.notification.rmq.serivce.RMQEventPublisher +import com.backgu.amaker.infra.rmq.config.RMQConfig +import org.springframework.amqp.core.AcknowledgeMode +import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory +import org.springframework.amqp.rabbit.connection.ConnectionFactory +import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter +import org.springframework.context.ApplicationEventPublisher +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Import + +@Configuration +@Import(RMQConfig::class) +class NotificationRMQEventPublisherConfig( + private val applicationEventPublisher: ApplicationEventPublisher, + private val jackson2JsonMessageConverter: Jackson2JsonMessageConverter, +) { + @Bean + fun rabbitListenerContainerFactory(connectionFactory: ConnectionFactory): RabbitListenerContainerFactory<*> { + val factory = SimpleRabbitListenerContainerFactory() + factory.setConnectionFactory(connectionFactory) + factory.setMessageConverter(jackson2JsonMessageConverter) + factory.setAcknowledgeMode(AcknowledgeMode.MANUAL) + return factory + } + + @Bean + fun notificationRMQEventPublisher(): RMQEventPublisher = RMQEventPublisher(applicationEventPublisher) +} diff --git a/infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/config/NotificationRMQProducerConfig.kt b/infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/config/NotificationRMQProducerConfig.kt new file mode 100644 index 00000000..cd43136f --- /dev/null +++ b/infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/config/NotificationRMQProducerConfig.kt @@ -0,0 +1,27 @@ +package com.backgu.amaker.infra.notification.rmq.config + +import com.backgu.amaker.application.notification.service.NotificationEventService +import com.backgu.amaker.infra.notification.rmq.serivce.NotificationRMQEventService +import com.backgu.amaker.infra.rmq.config.RMQConfig +import org.springframework.amqp.rabbit.connection.ConnectionFactory +import org.springframework.amqp.rabbit.core.RabbitTemplate +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Import + +@Configuration +@Import(RMQConfig::class) +class NotificationRMQProducerConfig( + private val jackson2JsonMessageConverter: Jackson2JsonMessageConverter, +) { + @Bean + fun rabbitTemplate(connectionFactory: ConnectionFactory): RabbitTemplate { + val rabbitTemplate = RabbitTemplate(connectionFactory) + rabbitTemplate.messageConverter = jackson2JsonMessageConverter + return rabbitTemplate + } + + @Bean + fun notificationRMQEventService(rabbitTemplate: RabbitTemplate): NotificationEventService = NotificationRMQEventService(rabbitTemplate) +} diff --git a/infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/serivce/NotificationRMQEventService.kt b/infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/serivce/NotificationRMQEventService.kt new file mode 100644 index 00000000..f19df805 --- /dev/null +++ b/infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/serivce/NotificationRMQEventService.kt @@ -0,0 +1,14 @@ +package com.backgu.amaker.infra.notification.rmq.serivce + +import com.backgu.amaker.application.notification.event.NotificationEvent +import com.backgu.amaker.application.notification.service.NotificationEventService +import com.backgu.amaker.infra.rmq.config.RMQConfig +import org.springframework.amqp.rabbit.core.RabbitTemplate + +class NotificationRMQEventService( + private val rabbitTemplate: RabbitTemplate, +) : NotificationEventService { + override fun publishNotificationEvent(notificationEvent: NotificationEvent) { + rabbitTemplate.convertAndSend(RMQConfig.NOTIFICATION_QUEUE, notificationEvent) + } +} diff --git a/infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/serivce/RMQEventPublisher.kt b/infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/serivce/RMQEventPublisher.kt new file mode 100644 index 00000000..3af3f2ea --- /dev/null +++ b/infra/src/main/kotlin/com/backgu/amaker/infra/notification/rmq/serivce/RMQEventPublisher.kt @@ -0,0 +1,37 @@ +package com.backgu.amaker.infra.notification.rmq.serivce + +import com.backgu.amaker.application.notification.event.NotificationEventWithCallback +import com.backgu.amaker.application.notification.mail.event.EmailEvent +import com.backgu.amaker.infra.rmq.config.RMQConfig +import com.rabbitmq.client.Channel +import org.springframework.amqp.rabbit.annotation.RabbitListener +import org.springframework.amqp.support.AmqpHeaders +import org.springframework.context.ApplicationEventPublisher +import org.springframework.messaging.handler.annotation.Headers + +class RMQEventPublisher( + private val applicationEventPublisher: ApplicationEventPublisher, +) { + @RabbitListener(queues = [RMQConfig.NOTIFICATION_QUEUE]) + fun publish( + notificationEvent: EmailEvent, + channel: Channel, + @Headers headers: Map, + ) { + val deliveryTag = headers[AmqpHeaders.DELIVERY_TAG] as Long + + applicationEventPublisher.publishEvent( + object : NotificationEventWithCallback { + override val notificationEvent = notificationEvent + + override fun postHandle() { + channel.basicAck(deliveryTag, false) + } + + override fun onFail(exception: Exception) { + channel.basicNack(deliveryTag, false, true) + } + }, + ) + } +} diff --git a/infra/src/main/kotlin/com/backgu/amaker/infra/rmq/config/RMQConfig.kt b/infra/src/main/kotlin/com/backgu/amaker/infra/rmq/config/RMQConfig.kt new file mode 100644 index 00000000..ad54f2fc --- /dev/null +++ b/infra/src/main/kotlin/com/backgu/amaker/infra/rmq/config/RMQConfig.kt @@ -0,0 +1,47 @@ +package com.backgu.amaker.infra.rmq.config + +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.rabbit.connection.CachingConnectionFactory +import org.springframework.amqp.rabbit.connection.ConnectionFactory +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter +import org.springframework.boot.context.properties.ConfigurationProperties +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +@ConfigurationProperties(prefix = "spring.rabbitmq") +class RMQConfig { + companion object { + const val NOTIFICATION_QUEUE = "notification" + const val NOTIFICATION_EXCHANGE = "notification" + const val NOTIFICATION_ROUTING_KEY = "notification" + } + + lateinit var host: String + var port: Int = 0 + lateinit var username: String + lateinit var password: String + + @Bean + fun jackson2JsonMessageConverter(): Jackson2JsonMessageConverter = Jackson2JsonMessageConverter() + + @Bean + fun queue(): Queue = Queue(RMQConfig.NOTIFICATION_QUEUE, false) + + @Bean + fun topicExchange(): TopicExchange = TopicExchange(RMQConfig.NOTIFICATION_EXCHANGE) + + @Bean + fun binding(): Binding = BindingBuilder.bind(queue()).to(topicExchange()).with(RMQConfig.NOTIFICATION_ROUTING_KEY) + + @Bean + fun connectionFactory(): ConnectionFactory { + val connectionFactory = CachingConnectionFactory(host, port) + connectionFactory.username = username + connectionFactory.setPassword(password) + return connectionFactory + } +} From 4f32c2bb8b76568c30f35b580aa3c0d0433bb12e Mon Sep 17 00:00:00 2001 From: Dltmd202 Date: Fri, 2 Aug 2024 13:16:23 +0900 Subject: [PATCH 3/3] =?UTF-8?q?chore:=20kapt=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/build.gradle.kts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/infra/build.gradle.kts b/infra/build.gradle.kts index 8abc9bf5..a2d8139f 100644 --- a/infra/build.gradle.kts +++ b/infra/build.gradle.kts @@ -8,6 +8,10 @@ plugins { group = "com.backgu.amaker" version = "0.0.1-SNAPSHOT" +kapt { + correctErrorTypes = true +} + repositories { mavenCentral() } @@ -31,9 +35,9 @@ dependencies { implementation("com.querydsl:querydsl-apt:5.0.0:jakarta") implementation("jakarta.persistence:jakarta.persistence-api") implementation("jakarta.annotation:jakarta.annotation-api") - //implementation("org.springframework.boot:spring-boot-starter-amqp") + implementation("org.springframework.boot:spring-boot-starter-amqp") - //testImplementation("org.springframework.amqp:spring-rabbit-test") + testImplementation("org.springframework.amqp:spring-rabbit-test") kapt("com.querydsl:querydsl-apt:5.0.0:jakarta") kapt("org.springframework.boot:spring-boot-configuration-processor")