package com.fizz.business.scheduled;

import com.fizz.business.utils.RedisLockUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;

import java.util.function.Consumer;

@Slf4j
@Async("threadPoolTaskExecutor")
@Component
@EnableScheduling
public abstract class BaseSchedule {

    /**
     * 默认key过期时间 1800秒
     */
    private static final int DEFAULT_EXPIRE_SECONDS = 1800;

    protected void execute(String taskName, int cacheSeconds, String cacheKey, Runnable func) {
        // 执行完2分钟 删除键值
        int delayedSeconds = Math.min(120, cacheSeconds / 10);
        execute(taskName, cacheSeconds, delayedSeconds, cacheKey, k -> func.run());
    }

    /**
     * 定时任务执行 多服务防止同时执行
     *
     * @param taskName:       任务名称
     * @param cacheSeconds:   <= 0时默认时间
     * @param delayedSeconds: 任务执行完延时删除key; <0时默认 cacheSeconds/10
     * @param cacheKey:
     * @param func:           执行的任务 key: 处理后的cacheKey
     */
    protected void execute(String taskName, int cacheSeconds, int delayedSeconds, String cacheKey, Consumer<String> func) {
        String threadName = Thread.currentThread().getName();
        cacheKey = "scheduling:" + cacheKey;
        if (cacheSeconds <= 0) {
            cacheSeconds = DEFAULT_EXPIRE_SECONDS;
        }
        if (delayedSeconds < 0) {
            delayedSeconds = cacheSeconds / 10;
        }
        // 不存在键值时执行
        String value = "1";
        boolean success = RedisLockUtil.setIfAbsent(cacheKey, value, cacheSeconds);
        if (!success) {
            log.debug("定时任务: {}, 取消执行. {}", taskName, threadName);
            return;
        }
        log.debug("定时任务: {}, 开始执行. {}", taskName, threadName);
        func.accept(cacheKey);
        // 执行完后 延时时间内不可重复执行
        if (delayedSeconds == 0) {
            RedisLockUtil.delLock(cacheKey, value);
        } else {
            RedisLockUtil.setIfPresent(cacheKey, value, delayedSeconds);
        }
        log.debug("定时任务: {}, 执行结束. {}", taskName, threadName);
    }

    public void actionCatchException(Runnable func) {
        String threadName = Thread.currentThread().getName();
        try {
            func.run();
        } catch (Exception e) {
            log.error("定时任务执行出错 " + threadName, e);
        }
    }


}
