package com.nanri.aiimage.config; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import java.time.Clock; import java.time.ZoneId; @Configuration @EnableScheduling @ConditionalOnProperty(prefix = "aiimage.scheduling", name = "enabled", havingValue = "true", matchIfMissing = true) @Slf4j public class SchedulingConfig { private static final ZoneId BUSINESS_ZONE = ZoneId.of("Asia/Shanghai"); /** * 调度线程池:承载全站 30+ 个 @Scheduled(含 imagevideo 1s 派发、5s 轮询、结果文件 worker 15s 等高频任务)。 * *

此前默认 4 线程:任一慢任务(如结果文件组装被内联执行时)都会把兜底类任务 * (StaleTaskRepair 心跳判死、陈旧扫描、历史清理)顺延,而兜底任务被顺延会直接放大线上故障面。 * 提到 16 并保持可配(aiimage.scheduling.pool-size)。 */ @Bean public TaskScheduler taskScheduler(@Value("${aiimage.scheduling.pool-size:16}") int poolSize) { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(Math.max(1, poolSize)); scheduler.setThreadNamePrefix("aiimage-scheduling-"); scheduler.setClock(Clock.system(BUSINESS_ZONE)); scheduler.setWaitForTasksToCompleteOnShutdown(true); scheduler.setAwaitTerminationSeconds(30); scheduler.setErrorHandler(ex -> log.warn("[scheduling] task execution failed: {}", ex.getMessage(), ex)); scheduler.initialize(); return scheduler; } }