본문 바로가기

분류 전체보기15

Spring boot 에서 종료되지 않은 스레드 모니터링 하기 목표애플리케이션을 개발하던 중 spring boot가 종료될 때 기존에 진행 중이던 작업들이 어떻게 안전하게 종료되는지 궁금해졌다그래서 아래 케이스에 대해 어떤 방식으로 종료되는지 확인하고, 안전하게 종료되지 않았을 경우 이를 어떻게 확인할 수 있는지도 알아보도록 하겠다. '안전하지 종료되지 않았다란' 해야 할 작업을 모두 끝내지 못하고 종료된 케이스를 의미한다 graceful shutdown이 활성화되고, shutdown timeout 이 5초이고, ThreadPoolTaskExecutor를 이용해서 비동기로 수행하던 작업이 5초 이상 걸릴 경우 코드를 통해 동작 살펴보기먼저 graceful shutdown이 활성화되고, shutdown timeout 이 5초이고, ThreadPoolTaskExecut.. 2025. 5. 5.
코루틴 withTimeoutOrNull과 Webclient 에 대해서 목적기존에 webClient를 이용해서 외부에 호출하는 메서드 A가 있었다. 이 메서드 A는 webClient에 timeout 1000ms를 걸어서 사용 중이었다. 그러다가 메서드 A의 로직을 그대로 사용하면서, timeout만 300ms로 줄이고 싶은 요구가 생겼다. 기존에 메서드 A를 다른 여러 코드에서 사용 중이었기 때문에 A 내부의 webClient의 timeout을 줄이는 건 위험도가 높아 보였다이를 해결하기 위해 새로운 코드를 작성할 때 메서드 A를 가져다 쓰고 그 상위에 withTimeoutNull이라는 함수를 사용했다  fun getData(): String? = runBlocking { withTimeoutOrNull(300) { delayWebClient.get() .. 2025. 4. 6.
Spring MVC & WebClient 에서 MDC 로깅하기 2 목적저번 글에 이어지는 글이다. 저번 글에서 스레드가 변경돼도 MDC를 유지하기 위해서 MDC를  스트림 콘텍스트에 저장해 두고, 로깅하기 직전에 스트림 콘텍스트에서 MDC를 꺼내와서 현재의 스레드 로컬에 주입해 주는 방법을 사용했다하지만 위 방법을 로깅하기 직전에 매번 스트림 콘텍스트에서 MDC를 꺼내와서 현재의 스레드 로컬에 주입해야 하는 불편함이 있다. 이번 글에서는 이 문제를 해결해 보도록 하겠다 아래는 문제 해결을 위한 기본 코드이다. 아래 코드에서는 'Third' 로깅하기 직전 상위 스트림에서 스트림 콘텍스트에서 MDC를 꺼내와 스레드 로컬에 주입하는 작업을 빠트렸기 때문에 'Third' 로깅의 MDC 값이 null 인걸 확인할 수 있다object ReactorMdc { const val.. 2025. 3. 22.
코루틴 내부에서 예외가 발생했을 때 목적저번 글에서 코루틴의 async, launch와 관련된 예외 케이스를 다뤘다. 하지만 좀 더 근본적으로 코루틴 내부에서 예외가 발생했을 때 어떻게 처리되는지 알고 싶어서 이 글을 작성하게 됐다 미리 알아둬야 하는 개념이 글을 읽기 전 미리 알아둬야 하는 개념이 있다. 그것은 바로 job이다. 코루틴도 job의 하나이다job의 특징에 대해 나열해 보도록 하겠다job은 취소가 가능하다job은 부모-자식 관계를 만들 수 있으며, 부모 job이 취소되면 자식 job들도 재귀적으로 취소된다자식 job이 예외를 던지면서 실패하면 부모 job에게 취소요청을 보낸다. 단 'CancellationException' 외의 예외일 때만 해당되며, 이 동작은 SupervisorJob에 의해 변할 수 있다코루틴에서 lauc.. 2025. 3. 8.
코루틴의 async 내에서 예외 발생 시 동작 목적코루틴을 이용하여 비동기 작업을 처리하던 중 'async'와 'launch' 내부에서 예외가 발생하면 어떻게 처리될지 궁금해졌다그래서 여러 글을 찾아보던 중 async 내부에서 예외가 발생하면, await을 호출하기 전까지는 예외가 발생하지 않는다는 글을 봤다async 내부에서 예외가 발생하면 그 즉시 자식, 부모 코루틴에 예외 및 취소 신호를 보내야 하지 않나?라는 의문점이 들었고 이 의문점을 해결하고자 글을 작성하게 됐다문제상황 재현먼저 async 내부에서 예외를 발생시키고 await 은 호출하지 않는 코드를 실행시켜 봤다. 아래 코드가 그 예이다fun withoutAwait() { val deferred = CoroutineScope(Dispatchers.IO).async{ .. 2025. 3. 3.
TransactionalEventListener 정리 이번 글에서는 TransactionalEventListener를 보면서 들었던 질문과 답을 정리해 볼 예정이다. 특히 TransactionalEventListener의 동작 중 'AFTER_COMMIT' 동작에 대해서 알아볼 예정이다분석의 기반이 되는 코드는 아래와 같다@Serviceclass CoffeeService( private val coffeeRepository: CoffeeRepository, private val eventPublisher: ApplicationEventPublisher) { @Transactional fun createCoffee(name: String): Coffee { val coffee = Coffee(name = name) .. 2025. 2. 23.