Skip to content

Commit 2041fc9

Browse files
committed
feat: DeadLetter 발생시 슬랙으로 알럿이 가게하고, 재수행 할 수 있도록 수정한다
1 parent 89dee77 commit 2041fc9

16 files changed

+291
-3
lines changed

.github/workflows/deploy.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ jobs:
8585
"ELASTIC_SEARCH_USER_NAME=${{ secrets.ELASTIC_SEARCH_USER_NAME }}"
8686
"ELASTIC_SEARCH_PASSWORD=${{ secrets.ELASTIC_SEARCH_PASSWORD }}"
8787
"QUIZ_APPROVE_TOKEN=${{ secrets.QUIZ_APPROVE_TOKEN }}"
88+
"RELAY_APPROVE_TOKEN=${{ secrets.RELAY_APPROVE_TOKEN }}"
8889
8990
- name: build and push filebeat
9091
uses: docker/build-push-action@v4

deploy/api/Dockerfile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ ARG ELASTIC_SEARCH_URIS
2020
ARG ELASTIC_SEARCH_USER_NAME
2121
ARG ELASTIC_SEARCH_PASSWORD
2222
ARG QUIZ_APPROVE_TOKEN
23+
ARG RELAY_APPROVE_TOKEN
2324

2425
ARG JAR_FILE=./*.jar
2526
COPY ${JAR_FILE} gitanimals-api.jar
@@ -43,7 +44,8 @@ ENV db_url=${DB_URL} \
4344
elastic_search_uris=${ELASTIC_SEARCH_URIS} \
4445
elastic_search_user_name=${ELASTIC_SEARCH_USER_NAME} \
4546
elastic_search_password=${ELASTIC_SEARCH_PASSWORD} \
46-
quiz_approve_token=${QUIZ_APPROVE_TOKEN}
47+
quiz_approve_token=${QUIZ_APPROVE_TOKEN} \
48+
relay_approve_token=${RELAY_APPROVE_TOKEN}
4749

4850
ENTRYPOINT java -Djava.net.preferIPv4Stack=true -jar gitanimals-api.jar \
4951
--spring.datasource.url=${db_url} \
@@ -65,4 +67,5 @@ ENTRYPOINT java -Djava.net.preferIPv4Stack=true -jar gitanimals-api.jar \
6567
--spring.elasticsearch.uris=${elastic_search_uris} \
6668
--spring.elasticsearch.username=${elastic_search_user_name} \
6769
--spring.elasticsearch.password=${elastic_search_password} \
68-
--quiz.approve.token=${quiz_approve_token}
70+
--quiz.approve.token=${quiz_approve_token} \
71+
--relay.approve.token=${relay_approve_token}

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ kotestExtensionSpringVersion=1.1.3
2424
testContainerVersion=1.20.6
2525

2626
### Netx ###
27-
netxVersion=0.4.7
27+
netxVersion=0.4.9
2828

2929
### Snowflake ###
3030
snowflakeVersion=5.2.5

src/main/kotlin/org/gitanimals/core/redis/RedisPubSubChannel.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ object RedisPubSubChannel {
77

88
const val SLACK_INTERACTED = "SLACK_INTERACTED"
99
const val SLACK_REPLIED = "SLACK_REPLIED"
10+
11+
const val DEAD_LETTER_OCCURRED = "DEAD_LETTER_OCCURRED"
1012
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package org.gitanimals.notification.app
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper
4+
import org.gitanimals.core.redis.TraceableMessageListener
5+
import org.gitanimals.notification.app.event.DeadLetterEvent
6+
import org.gitanimals.notification.domain.Notification
7+
import org.gitanimals.notification.domain.Notification.ActionRequest
8+
import org.gitanimals.notification.domain.Notification.ActionRequest.Style.PRIMARY
9+
import org.springframework.beans.factory.annotation.Qualifier
10+
import org.springframework.beans.factory.annotation.Value
11+
import org.springframework.data.redis.connection.Message
12+
import org.springframework.data.redis.core.StringRedisTemplate
13+
import org.springframework.stereotype.Component
14+
15+
@Component
16+
class SlackDeadLetterMessageListener(
17+
private val redisTemplate: StringRedisTemplate,
18+
private val objectMapper: ObjectMapper,
19+
@Qualifier("gitAnimalsDeadLetterSlackNotification") private val notification: Notification,
20+
@Value("\${relay.approve.token}") private val approveToken: String,
21+
): TraceableMessageListener(redisTemplate, objectMapper) {
22+
23+
override fun onMessage(message: Message) {
24+
runCatching {
25+
val deadLetterEvent = objectMapper.readValue(
26+
redisTemplate.stringSerializer.deserialize(message.body),
27+
DeadLetterEvent::class.java,
28+
)
29+
30+
val payloadWhenRelayButtonClicked = mapOf(
31+
"clicked" to "RELAY",
32+
"sourceKey" to "RELAY_DEAD_LETTER",
33+
"approveToken" to approveToken,
34+
"deadLetterId" to deadLetterEvent.deadLetterId
35+
)
36+
37+
notification.notifyWithActions(
38+
message = """
39+
:this_is_fine::this_is_fine::this_is_fine::this_is_fine::this_is_fine:
40+
DeadLetter
41+
---
42+
$deadLetterEvent
43+
---
44+
""".trimIndent(),
45+
actions = listOf(
46+
ActionRequest(
47+
id = "relay_action",
48+
name = "Relay",
49+
style = PRIMARY,
50+
interaction = payloadWhenRelayButtonClicked,
51+
)
52+
),
53+
)
54+
}
55+
}
56+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.gitanimals.notification.app.event
2+
3+
import org.rooftop.netx.api.SagaEvent
4+
5+
data class DeadLetterEvent(
6+
val traceId: String,
7+
val deadLetterId: String,
8+
val sagaEvent: SagaEvent,
9+
)

src/main/kotlin/org/gitanimals/notification/infra/SlackNotifiactions.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,9 @@ class GitAnimalsNewQuizCreatedSlackNotification(
9191
objectMapper: ObjectMapper,
9292
@Value(value = "\${slack.token}") token: String,
9393
) : SlackNotification(token, "C08GU67NV6W", objectMapper)
94+
95+
@Component
96+
class GitAnimalsDeadLetterSlackNotification(
97+
objectMapper: ObjectMapper,
98+
@Value(value = "\${slack.token}") token: String,
99+
) : SlackNotification(token, "C08M0R0GEKV", objectMapper)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.gitanimals.supports.deadletter
2+
3+
import org.gitanimals.core.IdGenerator
4+
import org.gitanimals.core.filter.MDCFilter
5+
import org.gitanimals.core.redis.AsyncRedisPubSubEvent
6+
import org.gitanimals.core.redis.RedisPubSubChannel.DEAD_LETTER_OCCURRED
7+
import org.rooftop.netx.api.SagaEvent
8+
import org.slf4j.MDC
9+
10+
data class DeadLetterEvent(
11+
private val deadLetterId: String,
12+
private val sagaEvent: SagaEvent
13+
): AsyncRedisPubSubEvent(
14+
traceId = runCatching { MDC.get(MDCFilter.TRACE_ID) }
15+
.getOrElse { IdGenerator.generate().toString() },
16+
channel = DEAD_LETTER_OCCURRED,
17+
)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.gitanimals.supports.deadletter
2+
3+
import org.rooftop.netx.api.SagaEvent
4+
import org.rooftop.netx.spi.DeadLetterListener
5+
import org.springframework.context.ApplicationEventPublisher
6+
7+
class DeadLetterEventPublisher(
8+
private val applicationEventPublisher: ApplicationEventPublisher,
9+
) : DeadLetterListener {
10+
11+
override fun listen(deadLetterId: String, sagaEvent: SagaEvent) {
12+
applicationEventPublisher.publishEvent(
13+
DeadLetterEvent(
14+
deadLetterId = deadLetterId,
15+
sagaEvent = sagaEvent,
16+
)
17+
)
18+
}
19+
}
20+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.gitanimals.supports.deadletter
2+
3+
import org.rooftop.netx.spi.DeadLetterRegistry
4+
import org.springframework.context.ApplicationEventPublisher
5+
import org.springframework.context.annotation.Bean
6+
import org.springframework.context.annotation.Configuration
7+
8+
@Configuration
9+
class DeadLetterListenConfigurer(
10+
private val deadLetterRegistry: DeadLetterRegistry,
11+
private val applicationEventPublisher: ApplicationEventPublisher,
12+
) {
13+
14+
@Bean
15+
fun deadLetterEventPublisher(): DeadLetterEventPublisher {
16+
return DeadLetterEventPublisher(applicationEventPublisher).apply {
17+
deadLetterRegistry.addListener(this)
18+
}
19+
}
20+
}

0 commit comments

Comments
 (0)