2020 年,因为新冠疫情原因很多行业交流会议被取消,这就涉及到如何处理退款,理想的场景是当我们在系统管理界面点击取消按钮时,就会在后台自动批量处理所有已付款用户的退款,然后给对应用户发送会议取消和退款成功通知。

编写任务类

对于这样的耗时操作,显然可以借助消息队列来异步处理。我们创建一个对应的会议取消任务类 CancelConference,在 handle 方法中,我们在 each 方法的匿名函数中为每一个参会者处理退款,并发送邮件通知:

处理队列任务超时

这里面,如果使用了第三方支付服务的话,退款需要涉及到网络请求,邮件发送也是个耗时操作,而 Laravel 任务类默认的超时时间是 60s,可能不够,你可以指定 --timeout 将其延长:

这里我们将其设置为了 300 分钟,也就是 5 个小时,之所以设置这么长,是因为 CancelConference 会在一次执行期间为所有参会者退款并发送通知。

当然,和 tries--backoff 等参数一样,你也可以通过任务类的属性设置超时时间:

推荐这样做,因为只有这个任务需要设置很长的超时时间,其他任务不需要这么长。

避免队列任务重复执行

从队列中获取任务时,任务被标记为 reserved,这样就不能被其他处理器获取了,当任务执行完成后,要么从队列中移除,要么再次被推送到队列重试。

但是如果队列任务在执行过程中队列处理器进程崩溃导致任务执行中断,则永远被标记为 reserved,不会再被执行。

要避免这个问题,Laravel 为 reserved 状态设置了超时时间,默认是 90s,可以在 queue.php 配置文件中配置这个值:

由于我们为 CancelConference 任务类设置了超时时间为 5 个小时,这会导致的一个问题是 90s 后,reserved 状态失效,其他处理器可以获取这个任务类执行,出现同一个任务的重复执行。

要解决这个问题,需要确保 retry_after 的值大于所有任务类的超时时间:

确保拥有足够多的处理器

如果一个任务需要执行 5 个小时,只有一个队列处理器进程的话,其他队列任务都会被堵塞,为此需要启动多个处理器进程,但是也有可能所有处理器进程同时都在执行这些耗时 5 小时的任务,一个解决办法是将这些任务推送到独立的队列:

并为其分配足够多的处理器进程:

使用独立的连接处理耗时任务

按住葫芦起了瓢,只有 1 个队列任务耗时 5 小时,却要连带所有其他任务的 reversed 状态需要 5 个多小时才能过期,这么做是不合适的,要解决这个问题,可以为该队列设置独立的连接:

然后在推送非常耗时的任务到队列的时候指定连接:

或者在任务类中通过属性值设置这个连接:

最后我们还可以在启动处理器进程的时候指定队列连接:

php artisan queue:work database-cancelations

指定连接的队列处理器进程只能消费该连接中的队列任务。

将单任务拆分为多个子任务

我们的 CancelConference 任务类可能需要运行长达 5 个小时才能完成所有退款和邮件发送,在此期间这个队列处理器进程只能处理这一个任务,如果在执行过程中出现异常,又要从头开始执行,并且跳过已经处理过的退款,这里面存在的不可控和风险比较大。

为此,我们可以将这个耗时很长的单任务分发拆分为多个子任务的分发,实现起来也不难,就是把原来一个任务处理所有退款和通知的实现代码:

调整为一个任务只处理一个用户的退款和通知,我们新建一个 RefundAttendee 任务类来处理这个工作,从外部传入 RefundAttendee 的就不再是 Conference 实例,而是 Attendee 实例了:

这样一来,我们就可以恢复到使用单个队列连接,也不需要配置那些额外的超时字段了:

这里,我们实际上是在一个队列任务(CancelConference)中将另一个队列任务(RefundAttendee)推送到消息队列进行处理。

消息队列之取消会议和自动退款处理相关推荐

  1. RabbitMQ总结(一)--消息队列RabbitMQ应答模式(自动、手动)

    原文链接 消息队列RabbitMQ应答模式(自动.手动) 为了确保消息不会丢失,RabbitMQ支持消息应答.消费者发送一个消息应答,告诉RabbitMQ这个消息已经接收并且处理完毕了.RabbitM ...

  2. 消息队列mqtt取消订阅的回调

    消息队列的回调,可以帮助我们知道任务的结果,无论是成功还是失败,我们可以根据结果执行不同的操作, 取消订阅的sdk源码 /*** Unsubscribe for messages, stop rece ...

  3. 大数据互联网架构阶段 QuartZ定时任务+RabbitMQ消息队列

    QuartZ定时任务+RabbitMQ消息队列 一 .QuartZ定时任务解决订单系统遗留问题 情景分析: 在电商项目中 , 订单生成后 , 数据库商品数量-1 , 但是用户迟迟不进行支付操作 , 这 ...

  4. linux查看kafka队列消息,Kafka消息队列-从开始到上线

    运行环境 操作系统:Windows 10 : Linux发行版:CentOS Linux release 7.6.1810 (Core) JDK版本:1.8.0_221 说在前面 kafka作为开源的 ...

  5. ThinkPHP 使用 think-queue 实现 redis 消息队列(超详细)

    简单介绍: 消息队列中间件是大型系统中的重要组件,已经逐渐成为企业系统内部通信的核心手段.它具有松耦合.异步消息.流量削峰.可靠投递.广播.流量控制.最终一致性等一系列功能,已经成为异步RPC的主要手 ...

  6. 最详解消息队列以及RabbbitMQ之HelloWorld

    1.消息队列 1.MQ的相关概念 1.什么是MQ MQ(message queue),从字面意思上看,本质是个队列,FIFO 先入先出,只不过队列中存放的内容是message 而已,还是一种跨进程的通 ...

  7. RabbitMQ(消息队列)浅记

    消息队列 PS:大二下学习RabbitMQ的随手小记 一.什么是 MQ MQ(message queue),从字面意思上看,本质是个队列,FIFO 先入先出,只不过队列中存放的内容是message 而 ...

  8. 学习纪录片:三、消息队列下—RbbitMQ

    目录 前言 一.死信队列 概念 产生原因 死信队列的架构图 二.延迟队列 概念 使用场景 三.优先级队列 四.惰性队列 使用场景 两种模式 性能对比 RabbitMQ集群 使用集群的原因 搭建集群步骤 ...

  9. [阶段4 企业开发进阶] 3. 消息队列--RabbitMQ

    文章目录 1 消息队列 1.1 MQ的概念 基本介绍 使用原因 MQ分类 如何选择 1.2 RabbitMQ RabbitMQ核心 工作原理 安装教程 2 Hello World 2.1 依赖 2.2 ...

最新文章

  1. Java扫描配置文件的注解_详解Spring框架注解扫描开启之配置细节
  2. 密码学===公钥和私钥解释
  3. Selenium2Lib库之输入常用关键字实战
  4. Python 交叉验证模型评估
  5. JFreeChart 1.0.6 用户开发指南(中文)
  6. Meaningless Sequence Gym - 102832D
  7. MacBook 调度中心设置
  8. s7-300 400plc应用技术_西门子S7300/400顺序功能图设计教程,看完豁然开朗!
  9. 130号:SpringBoot使用AOP
  10. 人工智能将为维护网络安全带来更多可能
  11. JWT(Json Web Token)介绍
  12. 邮件服务系统专题14:九层垃圾邮件过滤技术
  13. 群晖做网页服务器_群晖NAS服务器管理后台的登入教程
  14. macOS 12.4beta3 With OpenCore 0.8.1 and Clover and winPE黑苹果镜像
  15. 华为性格测试挂的原因是什么?这局怎么破?
  16. Amesim(七):amesim自带demo动力学模型研究
  17. HanLp的应用 - 真实使用
  18. 移远4g LTE模块at指令集合
  19. vue 项目中 zip 压缩包文件下载
  20. html页脚的话,HTML页脚footer标记

热门文章

  1. 计算机课堂热身游戏,简单的两款小游戏,带你回味和同学在电脑课上的时光
  2. springcloud-alibaba-sentinel(1)sentinel流量卫兵介绍
  3. UVA_12676_Inverting Huffman(哈夫曼树)
  4. Python numpy.abs和abs函数别再傻傻分不清了
  5. JavaScript isArray
  6. Excel 划分各分数段并统计各分数段的人数
  7. Qt for winrt结合Winrt API开发
  8. Word文档怎样添加图片?技巧分享!怎么在Word文档中加入图片?
  9. 关于独立DFS和域DFS板书
  10. 万年历单片机C语言报告,C语言单片机万年历系统设报告优秀文档.doc