如何高效处理Stripe待处理/失败支付的自动重试?
Stripe支付重试与订单处理方案
一、核心原则:复用原Payment Intent而非新建
不要创建新的Payment Intent,直接重试原交易即可——原Intent已关联客户、支付方式、订单元数据等关键信息,复用能保证数据一致性,也符合Stripe的最佳实践。
二、具体实现步骤
1. 订单状态追踪与队列触发
- 给订单表新增字段:
stripe_payment_intent_id(存储Stripe返回的Intent ID)、payment_status(枚举值:pending/failed/succeeded)、retry_count(记录重试次数,默认0)、created_at(订单创建时间)。 - 配置定时任务(比如Cron或框架自带的任务调度,如Laravel Scheduler),每1分钟扫描订单表,筛选出以下订单加入重试队列:
payment_status为pending或failed- 订单创建时间超过5分钟
retry_count未达上限(建议设为3次,避免无限重试)
2. 队列任务的重试逻辑
队列任务核心是调用Stripe的confirm接口重试原Payment Intent,PHP代码示例:
// 从队列获取订单信息 $order = getTargetOrder($queueItem); try { $stripe = new \Stripe\StripeClient('你的Stripe密钥'); // 重试原Payment Intent $paymentIntent = $stripe->paymentIntents->confirm( $order->stripe_payment_intent_id, [ 'payment_method' => $order->stripe_payment_method_id, // 需提前将支付方式ID存到订单表 'error_on_requires_action' => true, // 直接返回错误,跳过需用户交互的场景 'metadata' => ['retry_attempt' => $order->retry_count + 1] ] ); // 根据返回状态处理订单 if ($paymentIntent->status === 'succeeded') { // 标记订单完成,触发后续流程(如发货) updateOrderStatus($order->id, 'completed'); } elseif (in_array($paymentIntent->status, ['requires_payment_method', 'failed'])) { $order->retry_count += 1; $order->payment_status = 'failed'; $order->save(); // 达到重试上限则通知用户更换卡片 if ($order->retry_count >= 3) { notifyUser($order->user_id, '订单支付失败,请更换支付卡片'); } } } catch (\Stripe\Exception\ApiErrorException $e) { // 捕获Stripe接口错误(如卡片拒付、网络问题) $order->retry_count += 1; $order->payment_status = 'failed'; $order->error_msg = $e->getError()->message; $order->save(); if ($order->retry_count >= 3) { notifyUser($order->user_id, '订单支付多次失败,请更换支付卡片'); } }
3. 关键注意事项
- 存储支付方式ID:现有代码未保存
payment_method_id,建议在创建Payment Intent后,将该字段存入订单表,否则重试时无法指定原支付方式。 - 递增重试间隔:可设置递增的重试间隔(如第一次5分钟后,第二次15分钟后,第三次30分钟后),避免频繁重试影响用户体验。
- Webhook兜底:仍需配置Stripe Webhook监听
payment_intent.succeeded和payment_intent.failed事件,覆盖用户手动在Stripe后台完成支付的场景。 - 幂等性保障:队列任务要保证幂等,可通过「订单ID+重试次数」作为唯一标识,避免同一订单被重复处理。
三、现有创建Payment Intent代码的优化
补充存储关键字段,可选启用自动支付方式配置:
if($params['payment_method'] == 'stripe') { $paymentIntent = $stripe->paymentIntents->create([ 'shipping' => [ "name" => $uModel->full_name, "phone" => $params['billing_phone'], "address" => [ "city" => $params['billing_city'], "country" => $params['billing_country'], "line1" => $params['billing_address_1'], "line2" => $params['billing_address_2'], "postal_code" => $params['billing_postcode'], "state" => $params['billing_state'] ] ], 'amount' => $params['total_price']*100, 'currency' => 'usd', 'payment_method_types' => ['card'], 'metadata' => ['order_id' => $params['order_id']], 'customer' => $customer, 'description' => 'Company - orderid #'.$params['order_id'], 'automatic_payment_methods' => ['enabled' => true] // 可选:启用Stripe自动支付方式处理 ]); // 保存关键信息到订单表 saveOrderStripeData($params['order_id'], $paymentIntent->id, $params['payment_method_id']); $res['clientSecret'] = $paymentIntent->client_secret; $res['payment_method'] = "stripe"; }
内容的提问来源于stack exchange,提问作者Sheryar Khan
相关产品推荐
相关产品推荐

