spring定时任务ThreadPoolTaskScheduler使用注意事项之线程池大小
背景
最近小伙伴解决了一个工单,描述为“手工推送案件无法推,提示token失效”,当前工单状态为待关闭,解决方案为“东软接口不稳定造成的,东软的接口恢复正常后,问题解决”,然后找现场让他们关闭工单,现场反馈:今天现场又出现相同的问题了!!!依然是token失效,工单关不了了。
过程
确认问题应用及版本
让对方把错误截图发了一下,发现好像不是卷宗自己的应用,跟卷宗团队小伙伴确认了一下,这是个定制的小工具。要到源码看了下,版本很干净,也不需要跟现场要版本号了,直接看当前代码即可。
问题初次定位
token失效有可能是服务器与客户端时差较大导致的,让现场核实了一下,就差几秒,不是这个原因。
让现场复现一下问题,并跟代码,发现所有请求东软接口的地方都需要在请求头传递token信息,而这个token是单例的,初次使用时会实例化。
现在既然找到token赋值的位置,且是单例的,现在又失效了,重启一下一定能解决,让现场重启
重启后确实解决了,从而得出结论“咱们只有在启动的时候申请了一次token,以后就再也没申请过,东软设置了token超时自动过期”,看看能不能让东软那边设置token永不过期
问题再次定位
但是!人家东软说token有效期是固定的两小时,且出问题的应用之前已经平稳运行好几天了。
基于目前的结论来看,每2个小时就需要重启一次应用才会避免token失效呀,现在的现象明显不是这样,怎么肥事?
继续找代码吧,看看都哪儿操作到token这个属性了,然后就找到了一个定时任务!
原来人家写了每半小时刷新一次token,而半个小时是小于东软的2小时的,所以理论上不会出现token失效的问题,那下一步的方向是哪儿呢?
定时任务嘛,看任务是否成功执行了就可以,反正他原来也有日志。
搜索了一遍之前的日志,没找到成功刷新的日志,这是怎么肥事?历史日志看不出来,咱们就看新日志吧。
到时间后为什么定时任务没执行?来,看代码,看日志!
代码里之前已经看到了,用的是spring提供的ThreadPoolTaskScheduler
创建的定时器,没啥问题,看日志吧。
任务虽然执行成功了,但是日志有点儿怪呀,为什么刷新token的线程threadPoolTaskScheduler-1
还被其他实例使用了?又不是主线程,他们应该是分别使用自己的才对呀,去SyncDataService
看看。
哦哦,原来他们用的是同一个定时线程池的实例,扩散的看一下,原来有4个定时任务用的同一个实例。
那难道是他们在排队执行吗?去看一下ThreadPoolTaskScheduler
的实现,网上说默认他只有一个工作线程,如果存在多个任务被触发时,会等第一个任务执行完毕才会执行下一个任务,看了下源码确实是这样。
回过头来看看日志是否可以佐证我们的猜想,11点41项目启动成功,定时任务实例化成功。
12点 SyncMaterials
任务开始执行(直接搜 threadPoolTaskScheduler-1
即可,因为默认线程大小是1,所以所有任务的工作线程名称都是他)
12点26 SyncMaterials
任务执行完毕,开始执行 SyncDataService
12点35 SyncDataService
任务执行完毕,开始执行 ScheduleService
再看看之前几天的日志,佐证一下猜想,可以看到确实是差不多每半小时执行一次。
解决方案
1、手工设置ThreadPoolTaskScheduler
线程池大小,使其与定时任务数保持一致,每个任务用单独的工作线程,互不干扰(定时任务太多时其实存在资源浪费,每个任务都会有一个工作线程单独执行,间隔时间长且执行时间短的任务会始终占用着这个线程资源)
2、不要用spring自带的ThreadPoolTaskScheduler
了,自己使用ScheduledExecutorService
实现任务调度
3、找其他更合适的框架实现定时任务调度
结语
劲酒虽好,可不要贪杯哦!!!
脑子里为什么突然就有画面了???我还年轻,我一定不知道这些老年人才知道的广告词!!!
说正经的:不知道自己不知道->知道自己不知道->不知道自己知道->知道自己知道,咱们要努力做到最后面的那种境界。
套用到代码的世界就是,小白时期好多东西都不知道,定时任务都不知道是什么,只知道每天做自己已知的事儿,不就是增删改查嘛,有什么难的,大家都这样干,我也这样干;
后来听人家说了,有个定时任务的概念,spring可以实现这个功能,可以怎么用,自己遇到类似需求的时候,直接就去网上找关键字spring 定时任务
,管他天高路远,管他山高水长,用就完了,干就是了;
再后来掉的坑多了,就知道看源码了,知道去看spring定时任务的原理了,后续工作中也知道再用spring定时任务的时候需要避免采什么坑,如何避免了,一阵沾沾自喜;
但后来被别人问的多了,或者自己开窍了,就知道除了spring自带了定时任务执行器,还有很多其他的方式可以实现相同的功能,他们各自的适用场景及优劣势是什么,自己当前的业务场景更适合用哪一种?开始做技术选型及预研了,这才是我们要追求的目标。