背景
最近小伙伴解決了一個工單,描述為“手工推送案件無法推,提示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自帶了定時任務執行器,還有很多其他的方式可以實現相同的功能,他們各自的適用場景及優劣勢是什么,自己當前的業務場景更適合用哪一種?開始做技術選型及預研了,這才是我們要追求的目標。
