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

Laravel每分钟执行的调度任务重复触发Stripe转账API问题求助

解决方案
  • 首先给调度任务添加防重叠配置,修改Kernel.php中的调度代码:
$schedule->command('charge:debts')->everyMinute()->withoutOverlapping();

withoutOverlapping是Laravel调度自带的防任务重叠机制,会避免上一次任务未执行完成时新的任务进程启动,从源头避免多进程同时处理同一条数据的问题。

  • 给待处理债务记录查询加悲观锁+事务,同时为Stripe请求添加幂等Key,避免并发冲突和重复扣款,修改业务代码如下:
// 开启数据库事务
DB::beginTransaction();
try {
    // 查询时加行锁,其他进程无法读取当前匹配的待处理行,直到当前事务提交
    $active_debts = Debt::where([['status', '=', 0]])->with('channels')->lockForUpdate()->get();
    foreach($active_debts as $debt) {
        $stripe = new \Stripe\StripeClient(env('STRIPE_CODE'));
        $stripe->transfers->create([
            'amount' => $transfer_amount,
            'currency' => $currency,
            'destination' => 'XXXXXX',//acct_1GqQxFH4ie1ley5J
            'transfer_group' => 'Pltaform fees',
        ], [
            'stripe_account' => $merchant_code,
            // 新增幂等Key,用债务ID作为唯一标识,就算重复发起请求Stripe也只会执行一次转账
            'idempotency_key' => 'debt_transfer_' . $debt->id
        ]);

        Debt::where('id', $debt->id)->update([
            'status' => 1
        ]);
    }
    DB::commit();
} catch(\Stripe\Exception\InvalidRequestException $e) {
    DB::rollBack();
    // 原有异常处理逻辑
}
  • 可选优化:新增处理中中间状态,查询到待处理债务后先将状态更新为处理中(比如定义status=2为处理中),再发起Stripe请求,请求成功后更新为成功状态,失败后回滚为待处理或标记为失败,进一步缩小并发冲突的时间窗口。

内容的提问来源于stack exchange,提问作者Adrijus Jakučionis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 14:45:08