You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 8中如何在Job内调度Job?订单自动派单异常求助

业务场景

订单下达后,若司机60秒内未响应,需自动派给下一位司机,因此需在Laravel Job中调度另一个Job。

控制器index方法代码
public function index()
{
    $order = Order::create([
        'name' => "order1",
        "driver_id" => "1",
        "status" => "0",
        "price" => "500"

    ]);

    dispatch(new OrderPlacedJob($order))->delay(now()->addSecond(30));
}
OrderPlacedJob类代码
class OrderPlacedJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $order;

    public function __construct(Order $order)
    {
        $this->order = $order;
    }
    
    public function handle()
    {
        $order = $this->order;
        
        if ($this->order->status == '0') {
            $driver_id = $this->order->driver_id + 1;
            $this->order->driver_id = $driver_id;
            $this->order->save();
        }

        OrderPlacedJob::dispatch($order)->delay(now()->addSecond(30));
    }
}
问题

代码首次执行正常,给ID为1的司机派单后,若司机未响应,driver_id更新为2,但后续任务不再执行,求解决办法。

解决办法

问题原因分析

  • 模型序列化可能导致获取旧数据:虽然SerializesModels会在Job执行时重新加载模型,但直接使用$this->order仍可能存在数据不一致的情况。
  • 无限调度Job引发队列问题:原代码无论订单状态如何都会持续创建新Job,可能导致队列堆积、Worker内存溢出或崩溃。
  • 字段类型不匹配:driver_id在数据库中若为字符串类型,与整数运算可能引发隐性错误,导致Job失败。

具体修复步骤

1. 刷新模型并增加终止条件

修改OrderPlacedJob的handle方法,主动获取最新订单数据,并仅在订单未响应时继续调度Job:

public function handle()
{
    // 从数据库加载最新订单信息,避免使用序列化的旧实例
    $order = $this->order->fresh();
    
    // 订单不存在时直接退出
    if (!$order) {
        return;
    }

    if ($order->status == '0') {
        // 显式转换driver_id为整数,避免类型错误
        $driverId = (int)$order->driver_id + 1;
        $order->driver_id = $driverId;
        $order->save();
    }

    // 仅当订单仍未响应时,才调度下一个任务
    if ($order->status == '0') {
        OrderPlacedJob::dispatch($order)->delay(now()->addSeconds(30));
    }
}

2. 统一字段类型

检查数据库中driver_id字段类型,建议设置为INT类型。若必须使用字符串,修改运算逻辑:

$driverId = (string)((int)$order->driver_id + 1);

3. 检查队列Worker配置

  • 确保Worker持续运行:使用php artisan queue:work启动守护进程模式的Worker(Laravel 9+),或php artisan queue:work --daemon(Laravel 8及以下)。
  • 查看失败任务:执行php artisan queue:failed查看是否有失败的Job,根据错误信息排查问题。
  • 设置Job重试次数:在OrderPlacedJob类中添加重试配置,避免单次失败导致任务终止:
class OrderPlacedJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    // 设置最多重试5次
    public $tries = 5;

    // ... 其他代码
}

4. 优化调度逻辑(可选)

如果无限循环调度Job不符合需求,可以改用Laravel任务调度定期检查未响应订单:

// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
    $schedule->call(function () {
        // 筛选出未响应且超过30秒的订单(根据需求调整时间)
        Order::where('status', '0')
            ->where('created_at', '<=', now()->subSeconds(30))
            ->each(function ($order) {
                $driverId = (int)$order->driver_id + 1;
                $order->driver_id = $driverId;
                $order->save();
            });
    })->everyThirtySeconds();
}

内容的提问来源于stack exchange,提问作者Zaeem Syed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 02:55:23