| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- package com.xuekairui.user.config;
- import com.xuekairui.common.TraceIdGenerator;
- import lombok.extern.slf4j.Slf4j;
- import org.jetbrains.annotations.NotNull;
- import org.slf4j.MDC;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.core.task.TaskDecorator;
- import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
- import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
- import java.util.concurrent.Executor;
- import java.util.concurrent.ThreadPoolExecutor;
- /**
- * 异步任务与定时调度线程池配置
- */
- @Configuration
- @Slf4j
- public class AsyncConfig {
- /**
- * 审计日志专用线程池
- * 核心线程数2,最大线程数5,队列容量100
- * 拒绝策略:CallerRunsPolicy(队列满时由调用线程执行,保证日志不丢失)
- */
- @Bean("auditLogExecutor")
- public Executor auditLogExecutor() {
- ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
- executor.setCorePoolSize(2);
- executor.setMaxPoolSize(5);
- executor.setQueueCapacity(100);
- executor.setThreadNamePrefix("audit-log-");
- executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
- executor.initialize();
- return executor;
- }
- /**
- * 定时任务调度线程池
- *
- * <p>Spring 默认 @Scheduled 使用单线程(scheduling-1),所有定时任务串行执行,
- * 若某个任务阻塞会拖累其他任务。配置独立线程池后:
- * <ul>
- * <li>各 @Scheduled 方法可并发执行,互不阻塞</li>
- * <li>线程名前缀 scheduling- 便于日志排查</li>
- * <li>核心线程数 2 覆盖当前 2 个定时任务,预留扩容空间</li>
- * </ul>
- *
- * <p>当前定时任务:
- * <ul>
- * <li>PaymentOrderService.cleanupExpiredOrders() — 每分钟清理过期订单</li>
- * <li>CrawlerQuotaGrantService.cleanupExpiredGrants() — 每小时清理过期配额</li>
- * </ul>
- */
- @Bean
- public ThreadPoolTaskScheduler taskScheduler() {
- ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
- scheduler.setPoolSize(2);
- scheduler.setThreadNamePrefix("scheduling-");
- scheduler.setAwaitTerminationSeconds(60);
- scheduler.setWaitForTasksToCompleteOnShutdown(true);
- scheduler.setTaskDecorator(new MdcTraceIdTaskDecorator());
- scheduler.setErrorHandler(t ->
- log.error("定时任务执行异常", t));
- return scheduler;
- }
- /**
- * 定时任务 MDC 装饰器:为每个任务生成独立 traceId,便于无 HTTP 上下文时定位问题
- */
- public static class MdcTraceIdTaskDecorator implements TaskDecorator {
- private static final String TRACE_ID_KEY = "traceId";
- @NotNull
- @Override
- public Runnable decorate(@NotNull Runnable runnable) {
- return () -> {
- String traceId = generateTraceId();
- MDC.put(TRACE_ID_KEY, traceId);
- try {
- runnable.run();
- } finally {
- MDC.clear();
- }
- };
- }
- private String generateTraceId() {
- return TraceIdGenerator.generate();
- }
- }
- }
|