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是下次通知时间。

    简易代码如下:
    第一次通知失败:
  

 //通知失败if (IDBConstant.RESULT_ERROR.equals(status)) {logger.info("返回结果为error 将订单id存到redis中  orderId===" + orderId);//将订单号放到redis中String key = IDBConstant.SCYD_NOTIFY_PREFIX_PRE + orderId;//集合的通用key,根据这个key能获取到需要通知的订单集合redisClient.hset(IDBConstant.SCYD_NOTIFY_AGAIN_PRE, key, key);//通知次数redisClient.set(IDBConstant.SCYD_NOTIFY_NUM_PRE + orderId, "2");//下一次通知时间,应该跟次数有关,可以写个枚举类,将次数和下次的加长时间对应redisClient.set(IDBConstant.SCYD_NOTIFY_TIME_PRE + orderId, System.currentTimeMillis() + 10 * DateConstant.ONE_THOUSAND * DateConstant.SIXTY_SECONDS + "");}

 定时任务每隔一分钟获取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() 就是对当前的订单再次通知。
    如果通知失败,更新次数和下次通知时间。如果成功就移除。最后别忘记释放锁。
    方法如下:

public void doSCYDPayNotifyAgainHandler(String item, String notifyTime, String num,String applyNum) {taskAsyncPool.execute(new Runnable() {@Overridepublic void run() {String[] strs = item.split("_");String orderId = strs[1];logger.info("[通知]" + orderId + ":第" + num + "次任务启动");//根据orderId  获取订单信息//订单信息假装已经获取到了try {//发送请求//过程1//过程2//获取结果,成功的话if (IDBConstant.RESULT_SUCCESS.equals(status)) {//清空缓存数据redisClient.delKey(IDBConstant.SCYD_NOTIFY_NUM_PAY + orderId);redisClient.delKey(IDBConstant.SCYD_NOTIFY_TIME_PAY + orderId);//移除操作成功的redisClient.hdel(IDBConstant.SCYD_NOTIFY_AGAIN_PAY, item);} else {int count = Integer.parseInt(num);if(count==5) {//回调第五次还是失败,直接返回return;}//如果还是没有回调,更新回调时间redisClient.set(IDBConstant.SCYD_NOTIFY_TIME_PAY + orderId, notifyTime);count += 1;//更新回调次数redisClient.set(IDBConstant.SCYD_NOTIFY_NUM_PAY + orderId, count + "");}} catch (Exception e) {logger.error("[回调通知]" + item + ":{}第" + num + "次任务异常:method{}" ,e);redisClient.set(IDBConstant.SCYD_NOTIFY_TIME_PAY + orderId, notifyTime);int count = Integer.parseInt(num);count += 1;//更新回调次数redisClient.set(IDBConstant.SCYD_NOTIFY_NUM_PAY + orderId, count + "");} finally {//解锁redisClient.unLock(item);}}});}    

    这样多条线程执行,主线程从redis中获取待通知订单集合,另起线程做通知操作。
    每通知一单就是一条线程,延迟性也得到了比较好的解决,上面从数据库取的结果也可以多线程。
    线程池也是有上限的,无限获取很可能将内存和cpu耗尽。

    推荐第三种方式。redis+队列

 

    3. redis+队列


    将已经获取到的订单扔到队列中,在队列里执行 doSCYDPayNotifyAgainHandler(String item, String notifyTime, String num,String applyNum) 
    这个方法,延时和cpu问题就能比较好的解决了。
    至于丢失问题,暂时没考虑过。就目前来说,第二种方式够用。其他的只是有一些想法,欢迎交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/412861.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

断电启动+智能插座 七彩虹B460主板实现电脑远程开机

BIOS设置操作步骤&#xff1a; 1&#xff0c;开机按F2进入BIOS系统&#xff08;小提示&#xff1a;不同的主板按键不一样&#xff0c;开机应该有提示&#xff09; 2&#xff0c;高级模式 > 高级 > 电源管理设置 > 交流电源恢复后处理 > 选择“开机” 3&#xff0c…

[css] 如何自定义radio按钮的样式

[css] 如何自定义radio按钮的样式 选择器 input[type“radio”]现在几乎不用原生的radio&#xff0c;一是原生样式改成设计稿的样子太浪费时间&#xff0c;二是不同浏览器对于原生radio的展示还不一样。基于状态驱动的思想&#xff0c;用自定义按钮或其他元素来替代radio&…

myabtis 数字+逗号 传参问题 $和#

大家好&#xff0c;我是烤鸭&#xff1a; 遇到一个maybatis传参的问题。 如果传参是数字逗号的形式&#xff0c;比如1,2,3,4,5。 问题复现&#xff1a; 项目中查询sql和navicat查询sql结果不一致。 1 项目中&#xff1a; 如图所示&#xff0c;查到一条数据。 可以看到…

SpringBoot上传文件到本服务器 目录与jar包同级

前言 看标题好像很简单的样子&#xff0c;但是针对使用jar包发布SpringBoot项目就不一样了。 当你使用tomcat发布项目的时候&#xff0c;上传文件存放会变得非常简单&#xff0c;因为你可以随意操作项目路径下的资源。但是当你使用SpringBoot的jar包发布项目的时候&#xff0c;…

JS判断是否是科学计算结果并处理

var re 505899.24- 495991.61- 9907.63;var test1 /\d(?:.(\d*))?e([-]\d)/.test(re);alert("是否是科学计算结果:"test1);var test2 re.toFixed(10)-0;alert("处理后的结果&#xff1a;" test2 );

[css] css怎样使每个字符宽度一样?

[css] css怎样使每个字符宽度一样&#xff1f; 控制字符间距&#xff1a;letter-spacing:1em;[em,px,rem]个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe

大家好&#xff0c;我是烤鸭&#xff1a; 又是采坑实录。 异常如下&#xff1a; org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipeat org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:356)at org.ap…

[css] word-wrap、word-break和white-space有什么区别?

[css] word-wrap、word-break和white-space有什么区别&#xff1f; word-wrap标明是否允许浏览器再单词内进行断句normal 只允许在断字点换行 默认值break-word 在长单词或这url地址内部进行换行word-break标明怎么样进行单词内的断句normal 默认值break-all 允许在单词内换行k…

Redis免费客户端 Another Redis DeskTop Manager 下载地址及安装教程

下载及安装教程地址&#xff1a;GitHub - qishibo/AnotherRedisDesktopManager: &#x1f680;&#x1f680;&#x1f680;A faster, better and more stable redis desktop manager [GUI client], compatible with Linux, Windows, Mac. Whats more, it wont crash when loadi…

[css] 说说你对字母“X“在CSS中有什么作用?

[css] 说说你对字母"X"在CSS中有什么作用&#xff1f; 可以用作关闭按钮叉叉X的底部与文本对齐的基线位置相同个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面…

JavaScript文字转图片

非常感谢这位博主提供的代码&#xff0c;以下只做代码记录 博文转载地址&#xff1a;https://blog.csdn.net/qq_30100043/article/details/76549377//绘制文字到canvas&#xff0c;判断换行位置&#xff0c;和设置canvas高度 function canvasWrapText(options) {var settings …

mysql 内置功能 函数 date_format函数

创建数据库db12 create database db12 charsetutf8; use db12; 准备表和记录 CREATE TABLE blog (id INT PRIMARY KEY auto_increment,NAME CHAR (32),sub_time datetime ); 插入记录 INSERT INTO blog (NAME, sub_time) VALUES(第1篇,2015-03-01 11:31:21),(第2篇,2015-03-11 …

低版本webview无法请求jquery ajax

大家好&#xff0c;我是烤鸭&#xff1a; 又来踩坑了。 1. 场景复现 有反馈我们的H5页面&#xff0c;无法正确显示页面。就类似下图这样&#xff0c;ajax没法请求到数据。 之前测试的时候是在web端做的测试&#xff0c;用安卓7.0和8.0的手机都试了一下&#xff0c;是没…

[css] CSS3中的transition是否可以过渡opacity和display?

[css] CSS3中的transition是否可以过渡opacity和display&#xff1f; transition过渡display是有一个前提条件: 浏览器渲染是在每一帧的最后&#xff0c;每一帧都会执行以下操作:js执行2.style加持3.layout4.paint5.composite在js执行过程中&#xff0c; 遇到DOM操作&#xff…

Ubuntu 无法应用原保存的显示器配置

Ubuntu开机之后页面出现&#xff1a;无法应用原保存的显示器配置所选模式均不匹配可能的模式&#xff1a;为 CRTC 63 尝试模式CRTC 63&#xff1a;尝试 800x60060Hz 模式输出在 1366x76860Hz (通过 0)CRTC 63&#xff1a;尝试 2560x160060Hz 模式输出在 1366x76860Hz (通过 0)C…

由excel导出引起的cpu 100% 和gc 的问题

大家好&#xff0c;我是烤鸭&#xff1a; 记一次 由excel导出 导致的cpu飙升200%&#xff0c;jvm 内存不足。 1. 场景复现 前端页面导出Excel&#xff0c;之前导出4,5W条数据都没什么问题的。 今天业务突然反馈说导出不了了&#xff0c;我试着导出了2w数据&#xff0…

[css] 说下background-color:transparent和opacity:0的区别是什么?

[css] 说下background-color:transparent和opacity:0的区别是什么&#xff1f; background-color:transparent: 只是把背景色设置为透明&#xff0c;并不会影响元素中的内容。可以利用 transparent 进行三角、扇形的设置。opacity: 0: 会影响整个元素&#xff0c;元素的内容也会…

win11耳机和扬声器怎么分开控制音量?

win11耳机和扬声器怎么分开控制音量&#xff1f; 有时候有这种需求&#xff0c;在办公位置工作听耳机&#xff0c;拔掉耳机后&#xff0c;扬声器需要自动禁止声音 1&#xff0c;搜索并打开Realtek Audio Console 2&#xff0c;点击左下角“设备高级设置”&#xff0c;播放设备…

ngix莫名挂掉 signal process started

大家好&#xff0c;我是烤鸭&#xff1a; 又到了采坑实录。ngix莫名挂掉 error.log一直出现 signal process started 查看了access.log和error.log access.log&#xff1a; 43.245.218.208 - - [06/Jan/2019:18:08:43 0800] "GET / HTTP/1.1" 200 555 "-"…

[css] z-index有时不起作用的原因是什么?怎么解决?

[css] z-index有时不起作用的原因是什么&#xff1f;怎么解决&#xff1f; 根元素 (HTML),z-index 值不为 "auto"的 绝对/相对定位&#xff0c;一个 z-index 值不为 "auto"的 flex 项目 (flex item)&#xff0c;即&#xff1a;父元素 display: flex|inline…