# 订单失败自动重试机制

## 更新时间

2025-10-18

## 功能说明

为失败状态的订单添加自动重试机制，当用户再次请求创建订单或获取订单支付链接时，系统会自动尝试重新创建京东订单，直到成功为止。

## 核心特性

### 1. 智能失败检测

- 检测订单状态为 `OrderStatusCkFailed`(Ck失败状态)
- 在创建订单和获取支付链接时都会进行检测

### 2. 自动重试机制

- 失败订单被再次请求时自动触发重试
- 使用相同的重试逻辑(切换Cookie直到成功)
- 无需用户手动重新创建订单

### 3. 状态自动恢复

- 重试成功后自动从失败状态恢复为待支付状态
- 更新订单的京东订单ID和支付链接
- 记录完整的状态变更历史

## 流程图

### 创建订单流程(含失败重试)

```mermaid
graph TD
    A[用户请求创建订单] --> B{订单是否存在?}
    B -->|不存在| C[创建本地订单]
    B -->|存在| D{订单状态}
    
    D -->|待支付/已支付| E[返回现有订单]
    D -->|失败状态| F[触发自动重试]
    
    C --> G[尝试创建京东订单]
    F --> G
    
    G -->|成功| H[更新订单状态为待支付]
    G -->|失败| I[更新订单状态为失败]
    
    H --> J[返回支付链接]
    I --> K[返回错误信息]
    
    K -.再次请求.-> F
```

### 获取支付链接流程(含失败重试)

```mermaid
graph TD
    A[用户请求获取支付链接] --> B[查询订单]
    B --> C{订单状态}
    
    C -->|失败状态| D[触发自动重试]
    C -->|正常状态| E{支付链接是否过期?}
    
    D --> F[尝试创建京东订单]
    F -->|成功| G[更新为待支付状态]
    F -->|失败| H[保持失败状态]
    
    E -->|未过期| I[返回支付链接]
    E -->|已过期| J[刷新支付链接]
    
    G --> I
    H --> K[返回错误]
    J --> I
    
    K -.再次请求.-> D
```

## 代码修改详情

### 1. 新增方法

#### `retryCreateJdOrderForFailedOrder`

位置: `internal/logic/jd_cookie/order_create.go`

```go
// 为失败的订单重新创建京东订单
func (s *sJdCookie) retryCreateJdOrderForFailedOrder(
    ctx context.Context, 
    existingOrder *entity.V1JdCookieOrder, 
    req *model.CreateOrderReq
) (result *model.CreateOrderResult, err error)
```

**功能**:

- 尝试复用现有京东订单
- 如果无法复用,创建新的京东订单(带重试机制)
- 更新本地订单状态和关联关系
- 记录完整的历史记录

#### `updateOrderSuccess`

位置: `internal/logic/jd_cookie/order_utils.go`

```go
// 更新订单成功信息(从失败状态恢复)
func (s *sJdCookie) updateOrderSuccess(
    ctx context.Context, 
    orderId, 
    jdOrderId, 
    wxPayUrl string
) error
```

**功能**:

- 将失败状态的订单恢复为待支付状态
- 关联新的京东订单ID
- 记录状态恢复日志

### 2. 修改的方法

#### `CreateOrder`

位置: `internal/logic/jd_cookie/order_create.go`

**修改内容**:

```go
if existingOrder != nil {
    // 检查订单状态
    orderStatus := consts.OrderStatus(existingOrder.Status)
    
    // 如果是失败状态,触发重试
    if orderStatus == consts.OrderStatusCkFailed {
        return s.retryCreateJdOrderForFailedOrder(ctx, existingOrder, req)
    }
    
    // 正常状态,获取支付链接
    return s.GetPaymentUrl(ctx, req.UserOrderId, existingOrder.OrderId)
}
```

#### `GetPaymentUrl`

位置: `internal/logic/jd_cookie/order_query.go`

**修改内容**:

```go
// 检查订单状态,如果是失败状态,尝试重新创建京东订单
orderStatus := consts.OrderStatus(order.Status)
if orderStatus == consts.OrderStatusCkFailed {
    return s.retryCreateJdOrderForFailedOrder(ctx, order, &model.CreateOrderReq{
        UserOrderId: userOrderId,
        Amount:      gconv.Float64(order.Amount),
        Category:    consts.RedeemOrderCardCategory(order.Category),
    })
}
```

## 使用场景

### 场景1: 创建订单时Cookie不足

1. 用户创建订单,因Cookie全部不可用而失败
2. 系统补充了新的Cookie
3. 用户再次请求创建订单(使用相同的userOrderId)
4. **自动触发重试**,使用新Cookie创建成功
5. 返回支付链接

### 场景2: 获取支付链接时自动恢复

1. 订单创建失败,状态为`Ck失败`
2. 用户请求获取支付链接
3. **自动检测到失败状态并触发重试**
4. 重试成功,订单状态恢复为待支付
5. 返回有效的支付链接

### 场景3: 多次失败后成功

1. 第1次请求: 创建失败(Cookie不可用)
2. 第2次请求: 自动重试,仍然失败(Cookie仍不可用)
3. 第3次请求: 自动重试,**成功**(新的Cookie可用)
4. 订单状态从失败恢复为待支付

## 优势

### 1. 用户体验提升

- ✅ 无需手动重新创建订单
- ✅ 同一订单号可以多次重试
- ✅ 自动恢复,无需人工干预

### 2. 系统容错性增强

- ✅ 临时性故障可以自动恢复
- ✅ Cookie不足时可以等待补充后自动重试
- ✅ 减少失败订单积压

### 3. 运营成本降低

- ✅ 减少用户投诉
- ✅ 降低人工处理成本
- ✅ 提高订单成功率

## 重要说明

### 1. 幂等性保证

- 使用用户订单号(userOrderId)作为唯一标识
- 同一用户订单号只会创建一个本地订单
- 重试时不会创建新的本地订单,只更新现有订单

### 2. 安全性

- 重试过程中使用分布式锁
- 避免并发创建导致的数据不一致
- 完整的历史记录便于问题追溯

### 3. 性能考虑

- 重试逻辑只在检测到失败状态时触发
- 不影响正常订单的处理性能
- 使用异步记录历史,不阻塞主流程

## 监控建议

### 关键指标

1. **失败订单重试次数**: 监控平均重试次数
2. **重试成功率**: 重试成功订单 / 总重试订单
3. **失败订单恢复时间**: 从失败到成功的平均时长

### 告警规则

- 重试失败率 > 50%: 可能Cookie整体不可用
- 平均重试次数 > 3: Cookie补充不及时
- 失败订单积压 > 100: 需要人工介入

## 相关文件

- `internal/logic/jd_cookie/order_create.go`: 订单创建逻辑
- `internal/logic/jd_cookie/order_query.go`: 订单查询逻辑
- `internal/logic/jd_cookie/order_utils.go`: 订单工具方法
- `ORDER_CREATE_REFACTOR.md`: 订单创建流程重构文档

## 下一步优化建议

1. **智能重试间隔**: 根据失败次数调整重试间隔
2. **失败原因分类**: 区分不同类型的失败,针对性处理
3. **自动降级**: 连续失败时自动降级到其他支付方式
4. **主动通知**: 订单恢复成功后主动通知用户
