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
@@ -1,31 +1,42 @@
package site.icebang.global.config.asnyc;
package site.icebang.global.config.async;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskDecorator;
import org.springframework.core.task.support.ContextPropagatingTaskDecorator;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Configuration
@EnableAsync
@RequiredArgsConstructor
public class AsyncConfig implements AsyncConfigurer {

private final SemaphoreTaskDecorator semaphoreTaskDecorator;

@Bean("traceExecutor")
public ThreadPoolTaskExecutor traceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(100);
executor.setTaskDecorator(new ContextPropagatingTaskDecorator()); // 필수
public Executor traceExecutor() {
SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
executor.setVirtualThreads(true);
executor.setThreadNamePrefix("trace-");
executor.initialize();

// MDC 전파 데코레이터 생성
TaskDecorator contextDecorator = new ContextPropagatingTaskDecorator();

// 두 데코레이터의 조합:
// Context 설정(MDC 복사) 후 Semaphore 제어가 적용되도록 구성
executor.setTaskDecorator(
runnable -> contextDecorator.decorate(semaphoreTaskDecorator.decorate(runnable)));

return executor;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package site.icebang.global.config.async;

import java.util.concurrent.Semaphore;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.task.TaskDecorator;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class SemaphoreTaskDecorator implements TaskDecorator {

@Value("${spring.datasource.hikari.maximum-pool-size:10}")
private int maximumPoolSize;

private Semaphore semaphore;

@PostConstruct
public void init() {
this.semaphore = new Semaphore(maximumPoolSize);
log.info("SemaphoreTaskDecorator 초기화: 동시 실행 제한 수(maximumPoolSize) = {}", maximumPoolSize);
}

@Override
public Runnable decorate(Runnable runnable) {
return () -> {
try {
semaphore.acquire();
runnable.run();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("비동기 작업 실행 대기 중 인터럽트 발생", e);
} finally {
semaphore.release();
}
};
}
}
3 changes: 3 additions & 0 deletions apps/user-service/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
spring:
application:
name: mvp
threads:
virtual:
enabled: true
profiles:
active: develop
test:
Expand Down
Loading