定时任务模板代码
- 适用多微服务同时执行相同定时任务
- 适用于失败重试, 如每日8点,9点,10点执行定时任务,后两次用于检查是否需要失败重试
代码
- TaskTemplateCode.java
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import varyuan.po.Task;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
@EnableScheduling
public class TaskTemplateCode {
@Scheduled(fixedRate = 10 * 1000)
public void task1() {
templateCode();
}
@Scheduled(fixedRate = 10 * 1000)
public void task2() {
templateCode();
}
@Scheduled(fixedRate = 10 * 1000)
public void task3() {
templateCode();
}
@Resource
private TaskService taskService;
private void templateCode() {
log.info("定时任务--开始");
String taskName = "dev_test";
String taskSer = LocalDateTime.now().format(DateTimeFormatter.BASIC_ISO_DATE);
try {
Task task = taskService.select(taskName, taskSer);
if (task == null) {
if (taskService.insert(taskName, taskSer)) {
log.info("首次执行在本台机器");
exec();
taskService.updateSucc(taskName, taskSer);
} else {
log.info("首次执行在其他机器");
}
} else {
int status = task.getStatus();
if (status == TaskService.FAIL) {
if (taskService.updateRetryTimes(taskName, taskSer, task.getRetryTimes())) {
log.info("失败重试执行在本台机器");
exec();
taskService.updateSucc(taskName, taskSer);
} else {
log.info("失败重试执行在其他机器");
}
}
}
} catch (Exception e) {
taskService.updateFail(taskName, taskSer);
log.error("定时任务执行异常: ", e);
}
log.info("定时任务--结束");
}
private void exec() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
throw new RuntimeException();
}
}
- 定时任务表sql
CREATE TABLE `task` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`task_name` varchar(255) NOT NULL,
`task_ser` varchar(255) NOT NULL,
`status` int NOT NULL DEFAULT 0 COMMENT '任务执行状态,-1为失败,0为进行中,1为成功',
`retry_times` int NOT NULL DEFAULT '0' COMMENT '重试次数',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `unique_key` (`task_name`,`task_ser`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT '定时任务表';
- Task.java
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class Task {
private Long id;
private String taskName;
private String taskSer;
private Integer status;
private Integer retryTimes;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
- TaskDao.java
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import varyuan.po.Task;
public interface TaskDao {
@Select("select * from task where task_name=#{taskName} and task_ser=#{taskSer}")
Task select(@Param("taskName") String taskName, @Param("taskSer") String taskSer);
@Insert("insert into task(task_name,task_ser) values(#{taskName},#{taskSer})")
int insert(@Param("taskName") String taskName, @Param("taskSer") String taskSer);
@Update("update task set status=#{status} where task_name=#{taskName} and task_ser=#{taskSer}")
int updateStatus(@Param("taskName") String taskName, @Param("taskSer") String taskSer, @Param("status") int status);
@Update("update task set status=0,retry_times=retry_times+1 where task_name=#{taskName} and task_ser=#{taskSer} and retry_times=#{oldRetryTimes}")
int updateRetryTimes(@Param("taskName") String taskName, @Param("taskSer") String taskSer, @Param("oldRetryTimes") int oldRetryTimes);
}
- TaskService.java
import org.springframework.stereotype.Service;
import varyuan.dao.TaskDao;
import varyuan.po.Task;
import javax.annotation.Resource;
@Service
public class TaskService {
public static final int FAIL = -1;
public static final int RUNNING = 0;
public static final int SUCC = 1;
@Resource
private TaskDao taskDao;
public Task select(String taskName, String taskSer) {
return taskDao.select(taskName, taskSer);
}
public boolean insert(String taskName, String taskSer) {
try {
return taskDao.insert(taskName, taskSer) > 0;
} catch (Exception e) {
return false;
}
}
public boolean updateSucc(String taskName, String taskSer) {
return taskDao.updateStatus(taskName, taskSer, SUCC) > 0;
}
public boolean updateFail(String taskName, String taskSer) {
return taskDao.updateStatus(taskName, taskSer, FAIL) > 0;
}
public boolean updateRetryTimes(String taskName, String taskSer, int oldRetryTimes) {
return taskDao.updateRetryTimes(taskName, taskSer, oldRetryTimes) > 0;
}
}
cook
- spring执行定时任务
@Scheduled和异步任务@Async的线程池大小固定为1, 自定义线程池大小代码如下,更多信息参见@EnableScheduling注解的说明
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executors;
@Configuration
public class SimpleSchedulingConfigurer implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
}
}