redis实践的一点思路,关于支付回调
大家好,我是烤鴨:
如果作為第三方支付平臺,需要通知調用方付款成功。但是出現通知失敗的情況,怎么處理。
?? ?支付寶的異步通知,每個訂單的異步通知實行分頻率發送:15s 3m 10m 30m 30m 1h 2h 6h 15h。
?? ?如果沒有收到success,就會一直按上邊的進行通知。
?? ?就上述的情景說一下想到的解決方案,并不一定是有效的,只是一些想法:
?
?? ?1. 定時任務
?? ?最開始想到的是用定時任務來做。通知后,如果沒有收到結果,就會一直掃表。
?? ?掃描狀態是未通知的,下次通知的時間小于當前時間的,如果再通知再未送達到的話,
?? ?更新下次通知時間和通知次數。
?? ?這個做法有一些弊端,如果訂單到達一定數量,一直掃表會對數據庫壓力。
?? ?而且如果按照上面的時間間隔的話,在大量訂單的情況下很難保證精度。
?
?? ?2. 定時任務 + redis實現
?? ?為了避免數據庫的壓力,想到的是用redis來代替。
?? ?當第一次通知失敗的時候,將失敗的訂單標識(+訂單號)存到redis中。
?? ?其中redis中存放的是兩種數據結構,一種是Set集合,訂單號集合。
?? ?另一種String.key-value,key是前綴+訂單號,value是已通知次數。
?? ?還有一種是key是前綴+訂單號,value是下次通知時間。
?? ?簡易代碼如下:
?? ?第一次通知失敗:
??
?定時任務每隔一分鐘獲取redis數據
? // 獲取訂單號Set<String> list = redisClient.hkeys(IDBConstant.SCYD_NOTIFY_AGAIN_PAY);?? ?if (!list.isEmpty()) {list.forEach(item -> {String itemStr = (String) item;String[] strs = itemStr.split("_");String orderId = strs[1];String applyNum = redisClient.hget(IDBConstant.SCYD_NOTIFY_AGAIN_PAY, itemStr);System.out.println(IDBConstant.SCYD_NOTIFY_TIME_PAY + orderId);// 訂單發送的時間毫秒值String notifyTime = redisClient.get(IDBConstant.SCYD_NOTIFY_TIME_PAY + orderId);//被鎖不等待if (redisClient.tryLock(item, 0L, TimeUnit.SECONDS)) {// 如果通知時間 < 當前時間,發送通知if (Long.valueOf(notifyTime) < System.currentTimeMillis()) {// 通知次數String num = redisClient.get(IDBConstant.SCYD_NOTIFY_NUM_PAY + orderId);switch (num) {case "2":// 通知時間 + 10minnotifyTime = Long.valueOf(notifyTime)+ 20 * DateConstant.ONE_THOUSAND * DateConstant.SIXTY_SECONDS + "";doSCYDPayNotifyAgainHandler(item, notifyTime, num ,applyNum);break;case "3":// 通知時間 + 10minnotifyTime = Long.valueOf(notifyTime)+ 20 * DateConstant.ONE_THOUSAND * DateConstant.SIXTY_SECONDS + "";doSCYDPayNotifyAgainHandler(item, notifyTime, num ,applyNum);break;case "4":// 通知時間 + 15minnotifyTime = Long.valueOf(notifyTime)+ 30 * DateConstant.ONE_THOUSAND * DateConstant.SIXTY_SECONDS + "";doSCYDPayNotifyAgainHandler(item, notifyTime, num ,applyNum);break;case "5":// 通知時間 + 1h* DateConstant.SIXTY_MINUTESnotifyTime = Long.valueOf(notifyTime)+ 60 * DateConstant.ONE_THOUSAND * DateConstant.SIXTY_SECONDS + "";doSCYDPayNotifyAgainHandler(item, notifyTime, num ,applyNum);break;default:break;}}}});}?? ?上面方法中doSCYDPayNotifyAgainHandler()?就是對當前的訂單再次通知。
?? ?如果通知失敗,更新次數和下次通知時間。如果成功就移除。最后別忘記釋放鎖。
?? ?方法如下:
? ? 這樣多條線程執行,主線程從redis中獲取待通知訂單集合,另起線程做通知操作。
? ? 每通知一單就是一條線程,延遲性也得到了比較好的解決,上面從數據庫取的結果也可以多線程。
? ? 線程池也是有上限的,無限獲取很可能將內存和cpu耗盡。
? ? 推薦第三種方式。redis+隊列
?
?? ?3. redis+隊列
?? ?將已經獲取到的訂單扔到隊列中,在隊列里執行 doSCYDPayNotifyAgainHandler(String item, String notifyTime, String num,String applyNum)?
?? ?這個方法,延時和cpu問題就能比較好的解決了。
?? ?至于丟失問題,暫時沒考慮過。就目前來說,第二種方式夠用。其他的只是有一些想法,歡迎交流。
總結
以上是生活随笔為你收集整理的redis实践的一点思路,关于支付回调的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 上银驱动器使用手册_上银伺服电机调试说明
- 下一篇: 【Xamarin挖墙脚系列:最重要的布局