-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feat/#139] 구독시 디스코드 훅 / 신규 구독 안되는 문제 해결 #140
Changes from 10 commits
1fb2a02
8c25193
e131c6f
4a6f96b
56f9d36
f36b055
3b2dcc6
fa0b643
4d7df8a
0fba945
74c35a1
9161c98
19f380a
79e63ac
28adc89
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.few.api.repo.dao.subscription.record | ||
|
||
data class CountAllSubscriptionStatusRecord( | ||
val totalSubscriptions: Long, | ||
val activeSubscriptions: Long | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.few.api.client.config | ||
|
||
import org.springframework.beans.factory.annotation.Value | ||
import org.springframework.boot.web.client.RestTemplateBuilder | ||
import org.springframework.context.annotation.Bean | ||
import org.springframework.context.annotation.Configuration | ||
import org.springframework.web.client.RestTemplate | ||
import java.time.Duration | ||
|
||
@Configuration | ||
class ClientConfig { | ||
|
||
@Bean | ||
fun restTemplate( | ||
restTemplateBuilder: RestTemplateBuilder, | ||
@Value("\${client.timeout.connect}") connectTimeout: Int, | ||
@Value("\${client.timeout.read}") readTimeout: Int | ||
): RestTemplate { | ||
return restTemplateBuilder | ||
.setConnectTimeout(Duration.ofSeconds(connectTimeout.toLong())) | ||
.setReadTimeout(Duration.ofSeconds(readTimeout.toLong())) | ||
.build() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.few.api.client.config.properties | ||
|
||
data class DiscordBodyProperty( | ||
val content: String, | ||
val embeds: List<Embed> | ||
) | ||
|
||
data class Embed( | ||
val title: String, | ||
val description: String | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package com.few.api.client.subscription | ||
|
||
import com.few.api.client.config.properties.DiscordBodyProperty | ||
import com.few.api.client.config.properties.Embed | ||
import com.few.api.client.subscription.dto.WorkbookSubscriptionArgs | ||
import org.springframework.beans.factory.annotation.Value | ||
import org.springframework.http.HttpEntity | ||
import org.springframework.http.HttpMethod | ||
import org.springframework.stereotype.Service | ||
import org.springframework.web.client.RestTemplate | ||
|
||
@Service | ||
class SubscriptionClient( | ||
private val restTemplate: RestTemplate, | ||
@Value("\${webhook.discord}") private val discordWebhook: String | ||
) { | ||
fun announceWorkbookSubscription(args: WorkbookSubscriptionArgs) { | ||
args.let { | ||
DiscordBodyProperty( | ||
content = "🎉 신규 구독 알림 ", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. content는 따로 파일로 빼는게 좋을듯 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아 그 validation 하는 것 처럼 말이죠?! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 일단은 이렇게 가고 컨텐츠가 많아지거나 할 때 변경해도 좋을가 같아요 |
||
embeds = listOf( | ||
Embed( | ||
title = "Total Subscriptions", | ||
description = it.totalSubscriptions.toString() | ||
), | ||
Embed( | ||
title = "Active Subscriptions", | ||
description = it.activeSubscriptions.toString() | ||
), | ||
Embed( | ||
title = "Workbook Title", | ||
description = it.workbookTitle | ||
) | ||
) | ||
) | ||
}.let { body -> | ||
restTemplate.exchange( | ||
discordWebhook, | ||
HttpMethod.POST, | ||
HttpEntity(body), | ||
String::class.java | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기서 블락됨. 근데 응답 코드는 안가져오나요? 응답 로깅까지만이라도 하면 좋을거 같은데 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 바디가 No-content 라서 로깅을 할 수는 없을 것 같아요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 응답코드 로깅까지만 고고하시죠 |
||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.few.api.client.subscription.dto | ||
|
||
data class WorkbookSubscriptionArgs( | ||
val totalSubscriptions: Long, | ||
val activeSubscriptions: Long, | ||
val workbookTitle: String | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package com.few.api.domain.subscription.event | ||
|
||
import com.few.api.client.subscription.SubscriptionClient | ||
import com.few.api.client.subscription.dto.WorkbookSubscriptionArgs | ||
import com.few.api.domain.subscription.event.dto.WorkbookSubscriptionEvent | ||
import com.few.api.domain.subscription.service.WorkbookService | ||
import com.few.api.domain.subscription.service.dto.ReadWorkbookTitleDto | ||
import com.few.api.repo.dao.subscription.SubscriptionDao | ||
import org.springframework.context.event.EventListener | ||
import org.springframework.scheduling.annotation.Async | ||
import org.springframework.stereotype.Component | ||
|
||
@Component | ||
class WorkbookSubscriptionEventListener( | ||
private val subscriptionDao: SubscriptionDao, | ||
private val subscriptionClient: SubscriptionClient, | ||
private val workbookService: WorkbookService | ||
) { | ||
|
||
@Async | ||
@EventListener | ||
fun handleWorkbookSubscriptionEvent(event: WorkbookSubscriptionEvent) { | ||
val title = ReadWorkbookTitleDto(event.workbookId).let { dto -> | ||
workbookService.readWorkbookTitle(dto) | ||
?: throw RuntimeException("Workbook not found") | ||
} | ||
subscriptionDao.countAllSubscriptionStatus().let { record -> | ||
WorkbookSubscriptionArgs( | ||
totalSubscriptions = record.totalSubscriptions, | ||
activeSubscriptions = record.activeSubscriptions, | ||
workbookTitle = title | ||
).let { args -> | ||
subscriptionClient.announceWorkbookSubscription(args) | ||
} | ||
Comment on lines
+20
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아.. 그리고 “만약 디코 통신에서 에러 나면 우리 api도 실패로 처리할 것인가??” 가 중요할거 같은데 물론 저는 아니라고 생각해요. 그럼 try~catch를 활용해야 할거 같아요 이부분도 추가필요해보입니다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 첫 번째가 구독 UC 우선 웹훅을 보내는 것은 응답과 관련없는 기능이어 이를 이벤트로 처리하여 이를 분리하는 것이 좋겠다고 생각했습니다. @async를 통해 비동기로 처리할 때는 별도의 @transactional 전파 속성을 추가하지 않으면 UC의 트렌잭션이 전파되지 않아 3번째 댓글의 걱정은 하지 않아도 될 것 같습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아 네네 결국 제가 단 3번째 댓글로 인해서 어싱크로 가신거군요 좋습니다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
요거는 어떻게 설정하는게 좋을까요?
이전에는 요정도 설정햇습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. block io를 수행할 쓰레드이기 때문에 너무 적으면 안되고 구독 자체가 엄청 자주 발생할것 같진 않으니 적절히 max 10으로 갔다가 부하테스트 하면서 조절하는걸로 하시죠 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #173 에서 따로 처리하겠습니다! |
||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.few.api.domain.subscription.event.dto | ||
|
||
data class WorkbookSubscriptionEvent( | ||
val workbookId: Long | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.few.api.domain.subscription.service | ||
|
||
import com.few.api.domain.subscription.service.dto.ReadWorkbookTitleDto | ||
import com.few.api.repo.dao.workbook.WorkbookDao | ||
import com.few.api.repo.dao.workbook.query.SelectWorkBookRecordQuery | ||
import org.springframework.stereotype.Service | ||
|
||
@Service | ||
class WorkbookService( | ||
private val workbookDao: WorkbookDao | ||
) { | ||
|
||
fun readWorkbookTitle(dto: ReadWorkbookTitleDto): String? { | ||
return SelectWorkBookRecordQuery(dto.workbookId).let { query -> | ||
workbookDao.selectWorkBook(query)?.title | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.few.api.domain.subscription.service.dto | ||
|
||
data class ReadWorkbookTitleDto( | ||
val workbookId: Long | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
client: | ||
timeout: | ||
connect: 5000 | ||
read: 5000 | ||
|
||
webhook: | ||
discord: ${WEBHOOK_DISCORD} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
client: | ||
timeout: | ||
connect: ${TIMEOUT_CONNECT:5000} | ||
read: ${TIMEOUT_READ:5000} | ||
Comment on lines
+3
to
+4
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 5000이 5초인가요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 옙! |
||
|
||
webhook: | ||
discord: ${WEBHOOK_DISCORD} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RestTemplate 쓰면 동기로 처리하는걸로 알고 있어요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네 저도 알고 있지만, 지금 우리가 전부 비동기적으로 코드를 작성하고 있는게 아니기 때문에 익숙하지 않은 webclient 보다는 resttemplate을 우선 선택했어요!