package com.red.circle.mq.rocket.business.config;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * MQ 消息发送线程池配置.
 *
 * @author Leo
 */
@Slf4j
@Configuration
public class MqThreadPoolConfig {

  @Bean(name = "mqCallbackExecutor", destroyMethod = "shutdown")
  public ThreadPoolExecutor mqCallbackExecutor() {

    int corePoolSize = 50;        // 核心线程
    int maximumPoolSize = 300;    // 最大线程
    long keepAliveTime = 60L;
    int queueCapacity = 10000;    // 增大队列
    
    ThreadPoolExecutor executor = new ThreadPoolExecutor(
        corePoolSize,
        maximumPoolSize,
        keepAliveTime,
        TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(queueCapacity),
        new MqCallbackThreadFactory(),
        new MqCallbackRejectedHandler()
    );
    
    executor.allowCoreThreadTimeOut(false);
    
    log.info("MQ 回调线程池初始化完成 - 核心线程:{}, 最大线程:{}, 队列容量:{}", 
        corePoolSize, maximumPoolSize, queueCapacity);
    
    return executor;
  }
  
  private static class MqCallbackThreadFactory implements ThreadFactory {
    
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix = "mq-callback-";
    
    @Override
    public Thread newThread(Runnable r) {
      Thread thread = new Thread(r, namePrefix + threadNumber.getAndIncrement());
      thread.setDaemon(false);
      thread.setPriority(Thread.NORM_PRIORITY);
      return thread;
    }
  }
  
  private static class MqCallbackRejectedHandler implements RejectedExecutionHandler {
    
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
      log.error("MQ 回调线程池队列已满！当前线程数:{}, 队列大小:{}, 任务被拒绝", 
          executor.getPoolSize(), 
          executor.getQueue().size());
      
      if (!executor.isShutdown()) {
        r.run();
      }
    }
  }
}
