Laravel 实现创建订单30分钟未支付自动关闭的功能

前情提要

最近使用 Laravel 为一个带有订单支付的微信小程序提供后端 API 的开发。

客户提出如果用户创建订单后 30 分钟仍未支付就要关闭该订单并恢复商品sku的库存。

经过考虑,决定使用 延迟分发 的队列任务实现该功能。

什么是延迟分发

例如,让我们指定调度任务在 10 分钟后他被调度后才执行,在这之前任务不会被执行

如何实现延迟分发

我们只需在定义调度任务的时候,使用 Laravel 自带的 delay 方法即可实现。

实现步骤(真实代码)
确保安装 redis 并且项目正常可用
将 .env 中队列配置项指定为 redis
QUEUE_CONNECTION=redis
在项目 app 目录下创建 Jobs 子目录并创建 CloseOrder.php 实现延迟队列
<?php
namespace App\Jobs;

use App\Models\Order;
use App\Models\ProductSku;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;

/**
 * 30分钟未支付,关闭订单
 *
 * 代表这个类需要被队列中执行,而不是触发时立即执行
 *
 * Class CloseOrder
 * @package App\Jobs
 */
class CloseOrder implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $order;

    /**
     * Create a new job instance.
     *
     * @param Order $order
     * @param $delay 1800s
     * @return void
     */
    public function __construct(Order $order, $delay)
    {
        // 这里接收的是订单的实例
        $this->order = $order;
        // 核心配置:设置延迟的时间,delay()方法的参数代表多少秒之后执行
        $this->delay($delay);
    }

    /**
     * 定义这个任务类具体的执行逻辑
     * 当队列处理器从队列中取出任务时,会调用 handle() 方法
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        // 判断对应的订单是否已经被支付,如果已经支付则不需要关闭订单,直接退出
        if ($this->order->pay_at) {
            return;
        }

        // 通过事务执行 sql
        DB::transaction(function () {
                // 将订单的 closed 字段标记为2或指定值, 即关闭订单
                $this->order->update(['closed' => 2]);
                // 将订单中的库存数量加回到 SKU 的库存中去
                ProductSku::where('id', $this->order->sku_id)->increment('stock', $this->order->product_number);
            }
        );
    }
}
创建订单时调用上面的延迟调度任务
namespace App\Http\Controllers;

use App\Jobs\CloseOrder;

// 控制器逻辑
public function wechatPay(Request $request)
{
	// 事务创建订单,减库存等操作,这里忽略
	$order = DB::transaction(function(){
		......	
    });

    // 调用微信小程序统一下单接口
    $result = WxApp::MiniPay()->jsapi($data);
    
    // 调用延迟队列任务,超时30分钟未支付关闭订单,恢复库存
    dispatch(new CloseOrder($order, config('app.order_ttl')));
    
    // 返回给小程序,小程序调起微信支付
    return $this->success($result);
}
运行队列处理器
php artisan queue:work

技巧:为了让 queue:work 进程永久地在后台运行,您应该使用一个进程监视器,如 Supervisor,以确保队列 worker 不会停止运行。

Supervisor 的配置除官方文档介绍以外,也可参考我的另一篇文章:Centos7 x64搭建Web Server(PHP,Nginx,Mysql5.7/8,Redis,Supervisor) 找到 Supervisor安装与配置章节即可。

结论

通过以上的代码完美了实现了客户指定的功能,此类应用场景在业务开发中还有很多,转变一下思路都可以使用队列实现,这里不得不说 Laravel 已经封装好的队列模块确实强大。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吹落的树叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值