package com.cyksj.common.task;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ScheduledExecutorFactoryBean;
import org.springframework.scheduling.concurrent.ScheduledExecutorTask;
import org.springframework.stereotype.Component;

import java.util.concurrent.DelayQueue;

/**
 * @author chan
 * @className GlobalDelayQueueTask
 * @description 全局延时队列异步处理
 * @date 2020-05-21 16:35
 */
@Component
@Slf4j
public final class GlobalDelayQueueTask {

	private GlobalDelayQueueTask() {
	}

	private static final int CORE_SIZE = Runtime.getRuntime().availableProcessors();
	
	private static final GlobalDelayQueueTask INSTANCE = new GlobalDelayQueueTask();

	private static final GlobalThreadPoolTaskExecutor TASK_POOL = GlobalThreadPoolTaskExecutor.getInstance();
	
	private static final DelayQueue<BaseTaskBeanDelayed> DELAY_QUEUE = new DelayQueue<BaseTaskBeanDelayed>();

	private static final ScheduledExecutorFactoryBean SCHEDULED_FACTORY = new ScheduledExecutorFactoryBean();

	static {
		log.info("GlobalDelayQueueTask 线程池创建[start]");
		ScheduledExecutorTask task = new ScheduledExecutorTask();
		task.setDelay(0);
		task.setFixedRate(false);
		task.setPeriod(1000 * 15);
		task.setRunnable(new Runnable() {
			@Override
			public void run() {
				BaseTaskBeanDelayed taskBean = null;
				do {
					taskBean = DELAY_QUEUE.poll();
					if (taskBean != null) {
						TASK_POOL.execute(taskBean);
					}
				} while (taskBean != null);
			}
		});

		SCHEDULED_FACTORY.setScheduledExecutorTasks(task);
		// 调度遇到异常后,调度计划继续执行.
		SCHEDULED_FACTORY.setContinueScheduledExecutionAfterException(true);
		SCHEDULED_FACTORY.setThreadNamePrefix("YICANG_TASK_DELAY");
		SCHEDULED_FACTORY.setPoolSize(CORE_SIZE);
		SCHEDULED_FACTORY.initialize();
		log.info("GlobalDelayQueueTask 线程池创建[end]");
	}
	/**
	 * @author chan 获取单例对象
	 * **/
	public static GlobalDelayQueueTask getInstance() {
		return INSTANCE;
	}
	
	/**
	 * @author chan 覆盖任务执行
	 * **/
	public void compareAndSet(BaseTaskBeanDelayed taskBean) {
		if (DELAY_QUEUE.contains(taskBean)) {
			DELAY_QUEUE.remove(taskBean);
			DELAY_QUEUE.add(taskBean);
		} else {
			DELAY_QUEUE.add(taskBean);
		}
	}

}
