Spring Schedule默认串行,就是一个job执行完后,才执行第二个job
如果job1里面没有执行完,卡住了,那么后面的job就等待
目前线上遇到问题,job1里面有个发送钉钉通知的,发送钉钉的工具类被循环调用,发送的逻辑httpclient调用缺少超时设置,导致被卡主了,后面的job都没有执行,坑呀。
我们系统中有很凌晨半夜跑的job, 都是特别重要的job, 如果这些重要的job没有执行,那将是致命的, 所以这些必须执行的job是必须要执行的,如果这个job因为其他原因而阻塞了,这是天大的笑话。
用下面的代码还原下当时的场景:
@Scheduled(cron = "0 43 11 * * ?")
public void job1() {
LOGGER.info("job1 start ");
try {
for(int i=0; i<100; i++){
DingtalkRobotMsgUtil.sendTextMessage("测试钉钉超时消息,请忽略111!!!",systemConfig.getAccessToken());
Thread.sleep(50);
}
} catch (Exception e) {
e.printStackTrace();
}
LOGGER.info("job1 end ");
}
@Scheduled(cron = "0 44 11 * * ?")
public void job2() {
LOGGER.info("job2 start------------ ");
LOGGER.info("job2 end---------------------- ");
}
@Scheduled(cron = "0 */1 * * * ?")
public void job3() {
LOGGER.info("job3 start----3333------- ");
LOGGER.info("job3 end---------33333------------- ");
}
修复方案:
第一,将job修改为并行方式,其中一个job执行不影响后面的job
@Bean
public ScheduledThreadPoolExecutor scheduledExecutorService() {
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
return executor;
}
第二,httpclient调用的地方,设置超时
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000).setConnectionRequestTimeout(5000)
.setSocketTimeout(5000).build();
httppost.setConfig(requestConfig);
第三,在batch工程里面加上每分钟运行的心跳job, 方便后期观察系统job是否正常运行
@Scheduled(cron = "0 */1 * * * ?")
public void monitor() {
LOGGER.info("job is running ok");
}
总结:钉钉发送消息的工具类 超时时间设置, 从其他系统拷贝过来的工具类要详细看源码,例如超时时间是否设置,发送的方法是否改为异步,不要因为一些附加的通知发送影响业务主流程