自动取消已放弃的订单


自动取消过期订单

今天我们来看另一个需要借助消息队列异步处理的业务场景 —— 自动取消已经放弃的订单。

在网上购物商城,我们需要为已经下单的实体商品订单(尤其是限量的抢购订单,或者需要依赖商家及时响应的外卖订单)设置支付有效期,以免用户下单后长时间不支付,或者根本不打算支付,而又没有手动取消,白白占用了库存额度,让其他想买的用户无法购买。

有了支付有效期后(通常是 15 分钟、半小时或者一小时),超过这个有效期,我们就认为用户放弃这个订单了,然后系统会自动取消这个订单,释放对应库存。显然,这可以通过 Laravel 消息队列提供的延迟分发功能来实现。

延迟处理任务

假设这个监控订单状态并在过期后将其取消的队列任务类是 MonitorPendingOrder,对应的订单取消操作定义在 handle 方法中:

我们可以在分发这个队列任务时通过 delay 指定延迟时间:

这样一来,该任务就会在一小时后才会被推送到消息队列进行后续处理。

取消前发送提醒

当然,如果是用户真的忘记支付了,在取消前发送提醒消息会更友好一些,我们将订单监控任务类的 handle 处理代码调整如下:

这里使用了 release 延迟推送任务,其功能和 delay 等效。

然后每隔十五分钟给用户发送提醒,直到订单被取消:

确保队列任务执行了足够多的次数

前面我们已经说过,每次任务被推送到消息队列执行被都被看作尝试了一次,因此,按照上面这个逻辑,MonitorPendingOrder 这个任务类会被执行四次,如果配置的 tries 属性值小于 4 的话,那么订单将无法被取消,因为后续试图推送这个任务时,会被认为已经达到尝试次数上限而被丢弃,所以至少要将其最大尝试次数配置为 4:

队列任务延迟注意事项

另外一个需要注意的细节是,上面的延迟推送控制的时间点是任务推送到消息队列的时间,而任务真正执行的时间点是不可控的,如果队列很空闲,则其执行的时间点基本也能做到与预期相符,但如果队列负载很高,那么就要等到前面的所有任务处理完成后才能执行它,如果碰巧前面的任务是一个耗时任务,可能要等待几分钟甚至数小时,就与预期相差太多,到了不能接受的地步了,这个时候,可以运行多个队列处理器进程来尽可能快地提高队列任务处理速度,并且将这个任务的优先级调到更高。


Vote Vote Cancel Collect Collect Cancel

<< 上一篇: 重试执行失败的队列任务

>> 下一篇: 发送 Webhook 实现跨应用异步回调