场景
在业务中有时会碰到延迟操作,如下单后半小时未支付则取消订单、下单后十五分钟未支付则发短信提醒等等。那这样的需求如何去实现呢。
实现方式
- 第一个简单的方式就是用一个后台进程死循环去查订单,根据下单时间去做不同的操作
- 第二种就是使用消息队列的定时消息,下单之后发送定时消息,不同的定时队列去处理不同的逻辑
- 第三种可以使用框架提供的一些既有功能去做
实现代码
我们以订单创建 15 分钟后未支付,给用户发送邮件为场景进行学习
准备工作:
- 简单的订单表:order
- 各种需要的 composer 包
- rabbitMq 本地服务
- 开通阿里云 RocketMq 服务
第一种
- 代码逻辑很简单就直接死循环就行了
- 启动这个脚本进程,可以用 supervisor 配置
- 部分代码
//创建订单的逻辑
/**
* 随机创建订单
*/
$order = [
'order_number' => mt_rand(100,10000).date("YmdHis"),
'user_id' => mt_rand(1, 100),
'order_amount' => mt_rand(100, 1000),
];
/**@var $manager Illuminate\Database\Capsule\Manager **/
$conn = $manager;
$insertResult = $conn::table("order")
->insert($order);
print_r($insertResult);
延迟处理逻辑
while(true) {
// 未支付订单列表
$orderList = $conn::table("order")
->where("created_time", '<=', date("Y-m-d H:i:s", strtotime("-15 minutes")))
->where('sended_need_pay_notify', '=', 2)
->where('status', '=', 1)
->select(['user_id', 'id'])
->orderBy("id", 'asc')
->get();
$orderList = json_decode(json_encode($orderList), true);
foreach ($orderList as $orderInfo) {
sendEmail($orderInfo['user_id']);
$conn::table('order')
->where('id', '=', $orderInfo['id'])
->update(['sended_need_pay_notify' => 1]);
logs("update-success-orderId-". $orderInfo['id']."-userId-".$orderInfo['user_id']);
}
sleep(10);
}
执行处理脚本
gaoz@nobodyMBP delay_mq_demo % php first_while_handler.php
send email to 73 success ...
2020-06-24 11:37:36:update-success-orderId-3-userId-73
这种方式吧实现简单,但是不优雅,同时大批量订单产生也会遇到问题。
第二种
- 比如使用阿里云的 MQ 服务,目前 rocketMq 与 rabbitMq 版本支持延迟消息,但是 rabbit 的延时消息收费太高了
- 这里先使用 rocketMq 的延迟消息去实现
- 需要开通阿里云的服务
// 创建订单的逻辑
try
{