package com.zcxk.config;

import com.alibaba.fastjson.JSON;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

@Configuration
@Slf4j
@Data
public class AsyncConfig implements AsyncConfigurer {

    /**
     * 核心线程池大小
     */
    @Value("${aysnc.pool.core-size}")
    private Integer coreSize;
    /**
     * 最大线程池大小
     */
    @Value("${aysnc.pool.max-size}")
    private Integer maxSize;
    /**
     * 线程池队列容量（默认Integer.MAX_VALUE）
     */
    @Value("${aysnc.queue-capacity}")
    private Integer queueCapacity;
    /**
     * 线程池空闲时长（秒）
     */
    @Value("${aysnc.pool.keep-alive}")
    private Integer keepAlive;
    /**
     * 线程池名称
     */
    @Value("${aysnc.thread-name-prefix}")
    private String threadNamePrefix;

    /**
     * 配置异步线程池
     *
     * @return
     */
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(getCoreSize());
        executor.setMaxPoolSize(getMaxSize());
        //queueCapacity Integer.Max= 21 4748 3647
        executor.setQueueCapacity(getQueueCapacity());
        executor.setThreadNamePrefix(getThreadNamePrefix());
        executor.setKeepAliveSeconds(getKeepAlive());
        /** 拒绝异常处理 - 在调用线程中执行（当线程池中线程都以被占用且queue已满，则拒绝新提交的task，
         * 默认为ThreadPoolExecutor.AbortPolicy抛出异常到上层应用 - 导致异步调用死掉，无法再处理新任务，
         * 此处实现照搬ThreadPoolExecutor.CallerRunsPolicy且添加日志记录
         *
        executor.setRejectedExecutionHandler((r, e) -> {
            log.error("Async thread pool over load - caller run - queue.size={} - 请devops人员考虑扩展服务实例", e.getQueue().size());
            if (!e.isShutdown()) {
                r.run();
            }
        });*/
        // 设置拒绝策略：当pool已经达到max size的时候，如何处理新任务
        // CALLER_RUNS：不在新线程中执行任务，而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //如果不初始化，导致找到不到执行器（此语句需放到最后）
        executor.initialize();
        return executor;
    }

    /**
     * 异步线程池 - 全局异常处理
     *
     * @return
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (ex, method, params) -> {
            log.info("Async method: {} has uncaught exception, params:{}", method.getName(), JSON.toJSONString(params), ex);
        };
    }
}
