定时任务项目的设计思路:
1, 进程锁
2,任务的启动:(利用spring的@PostConstruct初始化后立即触发)
Parameters: SANXIANG(String)
LoanApplyJob List
HttpClientUtil.httpJsonPost(ApiUrls.LOAN_APPLY_URL, JSONObject.toJSON(loanApply).toString());--这些任务发送大这类任务的处理类
请求到TaskLoanApplyController:
loanApplyQueue 异步 自动触发
需要校验
loanApplyQueue -- String result = bankLoanApplyService.loanApply(loanApplyRequest); 进入自己的方法 (数据库配置实例) SanxiangLoanApplyServiceImpl(ioc获取任务中配置
好的处理类)
}
if (!riskLoanApplyService.checkTime(loanApply.getBankType())) {
return ApiResponse.error(CodeEnum.CODE_0040);
}
if (!riskLoanApplyService.checkCountAndAmt(loanApply)) {
return ApiResponse.error(CodeEnum.CODE_0046);
}
loanApply 手动调用用
RefreshController 可替代重启服务--重新加载数据库配置
TaskController 手动添加定时任务
对应配置:
b_bank_conf 待处理业务
b_bank_risk 专门配置定时任务允许的时间 等执行限制
task 大的进件任务
task_param 任务间隔
task_count_param 执行记录
task_timer(公用的非业务的定时任务)
AutoAdminTaskManager 开启调度---查task job表---组装任务 触发器---开启任务
AutoAdminTaskManager 查出任务
@PostConstruct 一在注入完成之后调用此方法,开启定时任务
BaseAdminTaskTimer
TaskTimerJobManager 这里启动
请求和返回参数记录日志
@PostConstruct
public void start() {
try {
System.out.println("*******");
//开启spring容器中的调度器,后续注入的都是已经开启的
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
LOG.info("StdSchedulerFactory >> start");
//开启调度器
scheduler.start();
LOG.info("StdSchedulerFactory >> end");
LOG.info("init clearRedisFlags >> start >> ");
//删除redis锁,每个任务执行前都会加上redis锁
clearRedisFlags();
LOG.info("init clearRedisFlags >> end >> ");
LOG.info("init startTasks >> start >> ");
//开启业务定时任务
startTasks();
LOG.info("init startTasks >> end >> ");
LOG.info("init startTaskTimers >> start >> ");
//开启公共定时任务
startTaskTimers();
LOG.info("init startTaskTimers >> end >> ");
LOG.info("init autoRefresh >> start >> ");
/*if (autoRefreshInterval < 30000 || autoRefreshInterval > 86400000) {
LOG.error("autoRefreshInterval to configure failed, it is lower than 30000 millisecond or higher than 86400000 millisecond");
autoRefreshInterval = 3000000;
}*/
baseTaskTimer.initData();
Runtime.getRuntime().addShutdownHook(new TaskShutdownHook(scheduler, redisService));
LOG.info("init autoRefresh >> end >> ");
} catch (Exception e) {
e.printStackTrace();
LOG.error("StdSchedulerFactory is exception >> " + e);
}
}
获取task任务表中的任务(每种业务一个大任务)
private void startTasks() {
LOG.info("AutoTaskListener >> list >> start3");
List
LOG.info("AutoTaskListener >> list >> end" + list);
for (Task taskTimer : list) {
baseTaskTimer.startTaskById(taskTimer);
}
}
/**
* 开始任务 根据配置好的实例id获取对应实例的对象-----job
*/
public void startTaskById(Task taskTimer) {
try {
LOG.info("startTaskById taskTimer >> " + taskTimer);
BaseJob job = (BaseJob) BaseBeanFactory.getBean(taskTimer.getTaskClass());
LOG.info("startTaskById job >> " + job);
if (null != job) {
job.reSet();
}
baseTaskTimerService.startTask(taskTimer, job);
} catch (Exception e) {
e.printStackTrace();
}
}
有了job之后组装trigger开始调度
@Override
public void startTask(Task taskTimer, BaseJob job) {
try {
if (taskTimer.getTaskType().equals(TaskType.FIX_DELAY.getCode())) { // 非定时任务
// 获取时间
Long delayDate = job.getDelayDate(JobConstants.AUTO_TASK_DELAY_DATE_KEY);
Long intervalDate = job.getIntervalDate(JobConstants.AUTO_TASK_INTERVAL_DATE_KEY);
JobDetail jobDetail = JobBuilder.newJob(job.getClass())
.withIdentity(taskTimer.getTaskClass(), Scheduler.DEFAULT_GROUP).build();
// 创建Trigger
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(intervalDate + "_" + taskTimer.getTaskClass(), Scheduler.DEFAULT_GROUP)
.startAt(new Date(new Date().getTime() + delayDate))
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInMilliseconds(intervalDate).repeatForever()).build();
scheduler.scheduleJob(jobDetail, trigger);
LOG.info("已调度非定时任务" + taskTimer.getTaskClass());
} else { // 定时任务
// 获取该任务的所有执行时间
List
if (null != timingDates && timingDates.size() > 0) {
// 创建 JobDetail
JobDetail jobDetail = JobBuilder.newJob(job.getClass()).withIdentity(taskTimer.getTaskClass(), Scheduler.DEFAULT_GROUP).storeDurably(true).build();
scheduler.addJob(jobDetail, false);
LOG.info("timingDates >> " + timingDates);
for (TimingDate timingDate : timingDates) {
Trigger trigger = null;
// 没有天 只有小时和分钟
if (timingDate.getDays() == 0) {
trigger = TriggerBuilder.newTrigger().forJob(jobDetail)
.withIdentity(timingDate.getHour() + "_" + timingDate.getMin() + "_" + taskTimer.getTaskClass(), Scheduler.DEFAULT_GROUP)
.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(timingDate.getHour(),timingDate.getMin())).build();
} else {
trigger = TriggerBuilder.newTrigger().forJob(jobDetail)
.withIdentity(timingDate.getHour() + "_" + timingDate.getMin() + "_" + taskTimer.getTaskClass(), Scheduler.DEFAULT_GROUP)
.withSchedule(CronScheduleBuilder.monthlyOnDayAndHourAndMinute(timingDate.getDays(),timingDate.getHour(), timingDate.getMin())).build();
}
if (null != trigger) {
scheduler.scheduleJob(trigger);
LOG.info("已调度定时任务 >> " + timingDates + taskTimer.getTaskClass());
}
}
LOG.info("已调度定时任务 >> " + timingDates + taskTimer.getTaskClass());
} else {
return;
}
}
} catch (Exception e) {
e.printStackTrace();
LOG.error("调度定时任务异常 >> " + taskTimer + " >> job >> " + job);
}
}
LoanApplyJob 具体的job类中用配置好的实例id获取要执行额具体服务
注意:
定时:
task_timer 公共的定时任务---注意 RUNNING
b_bank_conf 进件的定时任务-----注意 b_bank_risk也需要配置----配置有改动需要重启 task(大任务,RUNNING) 结合 task_param(执行时间间隔)
任务补偿:先是配置好自动发请求 一次失败之后会手动调用一个方法触发定时任务发请求跑指定次数(定时任务的补偿机制---还是没成功人工看任务的状态)
public void notify(LoanInfo loanInfo) throws Exception {
if (StringUtils.isNotBlank(loanInfo.getNotifyUrl())) {
//调用bank-task回调
String taskParams = MessageFormat.format(loanNotifyParam, loanInfo.getNotifyUrl(), JSONObject.toJSONString(getLoanResInfo(loanInfo)));
String[] p = taskParams.split("\\|");
TaskParam taskParam = new TaskParam();
taskParam.setTaskUrl(p[0]);
taskParam.setWaitingTime(p[1]);
taskParam.setPeriod(p[2]);
taskParam.setPartDelay(p[3]);
taskParam.setPartCount(p[4]);
taskParam.setExecutionCount(p[5]);
taskParam.setArgs(p[7]);
taskParam.setSuccessCdn(p[11]);
taskParam.setHttpType(p[15]);
sendTaskUtil.sendTask(taskParam);
}
}