項目中,因為使用了第三方支付(支付寶和微信支付),支付完畢后,第三方支付平臺一般會采用異步回調(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/