spring boot項目中處理Schedule定時任務(wù)

項目中,因為使用了第三方支付(支付寶和微信支付),支付完畢后,第三方支付平臺一般會采用異步回調(diào)通知的方式,通知商戶支付結(jié)果,然后商戶根據(jù)通知內(nèi)容,變更商戶項目支付訂單的狀態(tài)。一般來說,為了防止商戶項目自身因為一些特殊原因,比如正好當(dāng)時網(wǎng)絡(luò)狀態(tài)不穩(wěn)定,商戶回調(diào)接口無法訪問,或者商戶回調(diào)接口出現(xiàn)異常。第三方支付平臺,一般會發(fā)送多次請求來盡量確保通知到商戶系統(tǒng)。

但是,總會有各種各樣的情況,導(dǎo)致,第三方平臺所有的通知次數(shù)通知完畢后,商戶系統(tǒng)依然沒有正確處理掉改筆訂單狀態(tài)。(一般第三方支付平臺,會:1分鐘,10分鐘,1小時,6小時,12小時,24小時通知商戶支付接口,當(dāng)然這個時間只是舉例而已,實際的通知時間會和這個不太一樣,但是也是大致的意思)。當(dāng)如果按這個頻次通知完畢后,第三方支付平臺就不再進行通知了。

所以,一旦第三方支付平臺,將通知次數(shù)發(fā)送完畢后,平臺依然沒有處理好自己項目的訂單狀態(tài),那么訂單狀態(tài)很可能是,客戶實際已經(jīng)完成支付,但是自己項目這邊依然顯示:“等待支付”這樣的狀態(tài)。那么為了解決這類問題,一般,我們會采用定時任務(wù)的方式,比如1個小時,我們把訂單支付已經(jīng)超過1小時,但是還沒超過24小時的訂單去第三方平臺主動的查詢一次訂單狀態(tài)。避免因為自己原因,導(dǎo)致的訂單狀態(tài)不一致的情況。這類設(shè)置已經(jīng)超過1小時,未超過24小時的原因,主要是為了查詢效率,因為半小時之內(nèi)還未支付,我們認(rèn)為實際中存在這個可能性,所以可以等到1個小時,在查狀態(tài),而不超過24小時的原因是,一旦超過24小時,我們可以認(rèn)為訂單實際上已經(jīng)超時失敗了,如果查這個訂單,就會導(dǎo)致,每次定時任務(wù)都會把之前已經(jīng)查過的訂單,在反復(fù)的查詢。造成大量不必要的查詢。一般我們也會在啟一個定時任務(wù),24小時執(zhí)行一次,把一些訂單重置為失敗。減少不必要的失敗訂單的反復(fù)查詢。

下面進入正題,在spring boot中,如何來處理定時任務(wù)。
默認(rèn),springboot已經(jīng)支持了定時任務(wù)Schedule模塊,所以一般情況已經(jīng)完全能夠滿足我們的實際需求,一般來說,沒有必要在加入其他類似于:quartz

另外,在這里提一個實際項目中,關(guān)于定時任務(wù)的架構(gòu)上的一些考慮:

一般來說,實際項目中,為了提高服務(wù)的響應(yīng)能力,我們一般會通過負(fù)載均衡的方式,或者反向代理多個節(jié)點的方式來進行。通俗點來說,我們一般會將項目部署多實例,或者說部署多份,每個實例不同的啟動端口。但是每個實例的代碼其實都是一樣的。如果我們將定時任務(wù)寫在我們的項目中,就會面臨一個麻煩,就是比如我們部署了3個實例,三個實例一啟動,就會把定時任務(wù)都啟動,那么在同一個時間點,定時任務(wù)會一起執(zhí)行,也就是會執(zhí)行3次,這樣很可能會導(dǎo)致我們的業(yè)務(wù)出現(xiàn)錯誤。

一般來說,我們有幾種簡單的辦法來處理:

1、配置文件中增加自定義配置,通過開關(guān)來進行控制:比如增加:schedule=enable , schedule=disable,這樣在我們的實際代碼中,在進行判斷,也就是我們可以通過配置,達到,只有一個實例真正執(zhí)行定時任務(wù),其他的是實例不執(zhí)行。但是,這種做法實際是還是定時任務(wù)都啟動,只是在執(zhí)行中,我們?nèi)斯磉M行判斷,執(zhí)行于不執(zhí)行真正的處理邏輯。
2、邏輯分離,就是我們將真正要定時任務(wù)處理的邏輯,寫成rest服務(wù),或者rpc服務(wù),然后我們可以新建一個單獨的定時任務(wù)項目,這個項目應(yīng)該是沒有任何的業(yè)務(wù)代碼的,他純粹只有定時任務(wù)功能,幾點啟動,或者每隔多少時間啟動,啟動后,通過rest或者rpc的方式,調(diào)用真正處理邏輯的服務(wù)。同時,我們甚至可以不用新建一個項目,我們通過linux的cron就可以進行。同時,這種方式還有一個好處,比如有些時候,我們的定時任務(wù)也會因為某些原因出現(xiàn)問題,沒有執(zhí)行,那么我們就可以通過curl 或者wget等等很多方式,再次定時任務(wù)的執(zhí)行。

所以,個人一般偏向使用第二種方式,達到定時任務(wù)和業(yè)務(wù)處理的分離。

而在spring boot中,如何使用定時任務(wù),相對比較簡單。按第二種方式,實際上,我需要新建一個項目來完成定時任務(wù)的功能,其實,我們完全可以新建一個普通的java項目,引入quartz來達到,但是這里,我是通過spring boot來完成,新建一個spring boot項目,項目的初始化可以使用:http://start.spring.io

初始化之后,我們在spring boot的入口類Application.java中,允許支持schedule

@SpringBootApplication
@EnableScheduling
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

然后,新建一個執(zhí)行類Jobs.java

@Component
public class Jobs {
    public final static long ONE_Minute =  60 * 1000;
    
    @Scheduled(fixedDelay=ONE_Minute)
    public void fixedDelayJob(){
        System.out.println(Dates.format_yyyyMMddHHmmss(new Date())+" >>fixedDelay執(zhí)行....");
    }
    
    @Scheduled(fixedRate=ONE_Minute)
    public void fixedRateJob(){
        System.out.println(Dates.format_yyyyMMddHHmmss(new Date())+" >>fixedRate執(zhí)行....");
    }

    @Scheduled(cron="0 15 3 * * ?")
    public void cronJob(){
        System.out.println(Dates.format_yyyyMMddHHmmss(new Date())+" >>cron執(zhí)行....");
    }
}

這是最簡單的2種方式,多少分鐘執(zhí)行一次,fixedDelay和fixedRate,單位是毫秒,所以1分鐘就是60秒×1000
他們的區(qū)別在于,fixedRate就是每多次分鐘一次,不論你業(yè)務(wù)執(zhí)行花費了多少時間。我都是1分鐘執(zhí)行1次,而fixedDelay是當(dāng)任務(wù)執(zhí)行完畢后1分鐘在執(zhí)行。所以根據(jù)實際業(yè)務(wù)不同,我們會選擇不同的方式。

而還有一類定時任務(wù),比如是每天的3點15分執(zhí)行,那么我們就需要用另外一種方式:cron表達式

cron表達式,有專門的語法,而且感覺有點繞人,不過簡單來說,大家記住一些常用的用法即可,特殊的語法可以單獨去查。
cron一共有7位,但是最后一位是年,可以留空,所以我們可以寫6位:

* 第一位,表示秒,取值0-59
* 第二位,表示分,取值0-59
* 第三位,表示小時,取值0-23
* 第四位,日期天/日,取值1-31
* 第五位,日期月份,取值1-12
* 第六位,星期,取值1-7,星期一,星期二...,注:不是第1周,第二周的意思
          另外:1表示星期天,2表示星期一。
* 第7為,年份,可以留空,取值1970-2099

cron中,還有一些特殊的符號,含義如下:

(*)星號:可以理解為每的意思,每秒,每分,每天,每月,每年...
(?)問號:問號只能出現(xiàn)在日期和星期這兩個位置,表示這個位置的值不確定,每天3點執(zhí)行,所以第六位星期的位置,我們是不需要關(guān)注的,就是不確定的值。同時:日期和星期是兩個相互排斥的元素,通過問號來表明不指定值。比如,1月10日,比如是星期1,如果在星期的位置是另指定星期二,就前后沖突矛盾了。
(-)減號:表達一個范圍,如在小時字段中使用“10-12”,則表示從10到12點,即10,11,12
(,)逗號:表達一個列表值,如在星期字段中使用“1,2,4”,則表示星期一,星期二,星期四
(/)斜杠:如:x/y,x是開始值,y是步長,比如在第一位(秒) 0/15就是,從0秒開始,每15秒,最后就是0,15,30,45,60    另:*/y,等同于0/y

下面列舉幾個例子供大家來驗證:

0 0 3 * * ?     每天3點執(zhí)行
0 5 3 * * ?     每天3點5分執(zhí)行
0 5 3 ? * *     每天3點5分執(zhí)行,與上面作用相同
0 5/10 3 * * ?  每天3點的 5分,15分,25分,35分,45分,55分這幾個時間點執(zhí)行
0 10 3 ? * 1    每周星期天,3點10分 執(zhí)行,注:1表示星期天    
0 10 3 ? * 1#3  每個月的第三個星期,星期天 執(zhí)行,#號只能出現(xiàn)在星期的位置

?聲明:除非注明,本站所有文章皆為原創(chuàng),轉(zhuǎn)載請以鏈接形式標(biāo)明本文地址。
?轉(zhuǎn)載請注明來源:https://www.rjkf.cn/springboot-schedule-cron/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 純手工打造每一篇開源資訊與技術(shù)干貨,數(shù)十萬程序員和Linuxer已經(jīng)關(guān)注。 Cron 是UNIX中一個常見的工具,...
    塵世不擾閱讀 691評論 0 1
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,351評論 25 708
  • 安全生產(chǎn)標(biāo)準(zhǔn)化8要素 受限空間作業(yè) 安全生產(chǎn)標(biāo)準(zhǔn)化定義
    雨田_2bfc閱讀 156評論 0 0
  • 不知道為何,漸漸喜歡上一個之前從未有過感覺的女孩,也不知道為什么,開始害怕失去,害怕不理解我,可是又不敢挑明課說,...
    年回2017閱讀 361評論 0 1
  • 誤入花海,亦或成全不了一樁姹紫嫣紅的花事,卻等來半個世紀(jì)凋零的悲傷。傾城一夢,蕭蕭遺風(fēng),不惹風(fēng)塵,誤入紅塵,且待晨...
    霖雨凌零閱讀 697評論 0 2

友情鏈接更多精彩內(nèi)容