package com.nanri.aiimage.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; @Configuration public class TaskFileJobConfig { @Bean("taskFileJobDispatchExecutor") public TaskExecutor taskFileJobDispatchExecutor( @Value("${aiimage.result-file-job.local-dispatch-pool-size:2}") int poolSize, @Value("${aiimage.result-file-job.local-dispatch-queue-capacity:200}") int queueCapacity) { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); int normalizedPoolSize = Math.max(1, poolSize); executor.setCorePoolSize(normalizedPoolSize); executor.setMaxPoolSize(normalizedPoolSize); executor.setQueueCapacity(Math.max(10, queueCapacity)); executor.setThreadNamePrefix("task-file-job-dispatch-"); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(30); executor.initialize(); return executor; } @Bean(destroyMethod = "shutdown") public ExecutorService cozeVirtualThreadExecutor() { return Executors.newThreadPerTaskExecutor(Thread.ofVirtual() .name("coze-task-", 0) .factory()); } @Bean("cozeTaskExecutor") public TaskExecutor cozeTaskExecutor( ExecutorService cozeVirtualThreadExecutor, @Value("${aiimage.coze-task.max-concurrent:8}") int maxConcurrent) { Semaphore semaphore = new Semaphore(Math.max(1, maxConcurrent)); return new ConcurrentTaskExecutor(command -> cozeVirtualThreadExecutor.execute(() -> { boolean acquired = false; try { semaphore.acquire(); acquired = true; command.run(); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } finally { if (acquired) { semaphore.release(); } } })); } }