Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import kr.dongchimi.core.common.exception.CommonErrorCode
import kr.dongchimi.core.common.exception.CoreException
import kr.dongchimi.core.common.exception.ErrorCode
import kr.dongchimi.core.monitoring.ErrorContext
import kr.dongchimi.core.monitoring.ErrorNotificationDispatcher
import kr.dongchimi.gateway.logging.MdcFilter.Companion.REQUEST_ID
import kr.dongchimi.gateway.logging.MdcFilter.Companion.USER_ID
import org.slf4j.MDC
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package kr.dongchimi.api.core.common.exception
package kr.dongchimi.core.monitoring

import io.github.oshai.kotlinlogging.KotlinLogging
import jakarta.annotation.PreDestroy
Expand All @@ -8,16 +8,14 @@ import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.slf4j.MDCContext
import kr.dongchimi.core.monitoring.ErrorContext
import kr.dongchimi.core.monitoring.ErrorNotifier
import org.springframework.stereotype.Component

private val logger = KotlinLogging.logger {}

/**
* 미처리 예외 알림을 요청 스레드에서 분리해 비동기(fire-and-forget)로 발송한다.
* 미처리 예외 알림을 호출 스레드에서 분리해 비동기(fire-and-forget)로 발송한다.
*
* [ErrorContext]는 반드시 요청 스레드에서 완성해 넘겨야 한다. MDC·HttpServletRequest는
* [ErrorContext]는 반드시 호출 스레드에서 완성해 넘겨야 한다. MDC·HttpServletRequest는
* ThreadLocal/요청 스코프라 코루틴 스레드에서 접근하면 값이 유실되기 때문이다.
*/
@Component
Expand All @@ -26,7 +24,7 @@ class ErrorNotificationDispatcher(
private val scope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO),
) {
fun dispatch(context: ErrorContext) {
// dispatch()는 요청 스레드에서 호출됨 → 그 시점 MDC를 MDCContext로 캡처해 코루틴에 전파한다.
// dispatch()는 호출 스레드에서 실행됨 → 그 시점 MDC를 MDCContext로 캡처해 코루틴에 전파한다.
scope.launch(MDCContext()) {
errorNotifiers.forEach { notifier ->
runCatching { notifier.notify(context) }
Expand All @@ -35,6 +33,22 @@ class ErrorNotificationDispatcher(
}
}

fun dispatchJob(
throwable: Throwable,
jobId: String,
) {
dispatch(
ErrorContext(
throwable = throwable,
requestId = null,
userId = null,
requestMethod = null,
requestUri = null,
requestBody = "jobId=$jobId",
),
)
}

@PreDestroy
fun shutdown() {
scope.cancel()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import kotlinx.coroutines.withContext
import kr.dongchimi.core.monitoring.ErrorNotificationDispatcher
import kr.dongchimi.core.product.DraftFailReasonResolver
import kr.dongchimi.core.product.DraftStatus
import kr.dongchimi.core.product.PreparedProduct
Expand Down Expand Up @@ -55,6 +56,7 @@ class ImportJobProcessor(
private val importJobCancelSignal: ImportJobCancelSignal,
private val importJobFinisher: ImportJobFinisher,
private val draftFailReasonResolver: DraftFailReasonResolver,
private val errorNotificationDispatcher: ErrorNotificationDispatcher,
private val properties: ImportJobProperties,
) : ImportJobRunner {
override suspend fun run(
Expand Down Expand Up @@ -86,6 +88,7 @@ class ImportJobProcessor(
),
)
}
errorNotificationDispatcher.dispatchJob(e, job.jobId)
} finally {
leaseRenewal.cancel()
}
Expand Down
Loading