- 移除不必要的配置字段和复杂错误类型 - 简化trace和log初始化逻辑,保留核心功能 - 使用标准Go错误替代自定义错误结构 - 启用默认批处理和消息丢弃机制- 保留gzip压缩和自动重连功能- 更新相关文档路径引用 - 添加OTel简化增强实现说明文档
14 KiB
14 KiB
订单创建逻辑优化更新说明
📋 更新概述
根据需求,对京东Cookie订单创建逻辑进行了进一步优化,主要包括以下三个方面的改进:
- 刷新支付链接传递订单ID:替换随机UUID,使用实际订单ID
- GetPaymentUrl支付链接刷新失败降级:刷新失败时自动创建新京东订单
- 移除重试次数限制:无限重试直到没有可用Cookie为止
🔧 详细变更
1. 刷新支付链接传递订单ID
文件:internal/logic/jd_cookie/order_utils.go
变更前:
func (s *sJdCookie) refreshPaymentUrl(ctx context.Context, jdOrderId, payId, cookieId string) (wxPayUrl string, err error) {
// ...
appResp, err := originalJd.NewClient().RefreshPayment(ctx, &originalJd.RefreshPaymentReq{
Cookies: cookie.CookieValue,
OrderId: jdOrderIdInt,
PayId: payId,
UserOrderId: utils.GenerateRandomUUID(), // 使用随机UUID
})
// ...
}
变更后:
func (s *sJdCookie) refreshPaymentUrl(ctx context.Context, jdOrderId, payId, cookieId, orderId string) (wxPayUrl string, err error) {
// ...
appResp, err := originalJd.NewClient().RefreshPayment(ctx, &originalJd.RefreshPaymentReq{
Cookies: cookie.CookieValue,
OrderId: jdOrderIdInt,
PayId: payId,
UserOrderId: orderId, // 使用实际订单ID
})
// ...
}
改进点:
- ✅ 传递真实订单ID,便于追踪
- ✅ 移除对
utils.GenerateRandomUUID()的依赖 - ✅ 所有调用该方法的地方都需要传递orderId参数
影响范围:
order_create.go- 订单复用时刷新支付链接order_query.go- 获取支付链接时刷新
2. GetPaymentUrl 刷新失败自动降级
文件:internal/logic/jd_cookie/order_query.go
变更前:
func (s *sJdCookie) GetPaymentUrl(ctx context.Context, orderId string) (...) {
// ...
if jdOrder.WxPayExpireAt != nil && gtime.Now().After(jdOrder.WxPayExpireAt) {
// 支付链接已过期,尝试刷新
newWxPayUrl, err2 := s.refreshPaymentUrl(ctx, jdOrder.JdOrderId, jdOrder.PayId, jdOrder.CookieId)
if err2 != nil {
return "", "", "", gerror.Wrap(err, "刷新支付链接失败") // 直接返回错误
}
wxPayUrl = newWxPayUrl
}
// ...
}
变更后:
func (s *sJdCookie) GetPaymentUrl(ctx context.Context, orderId string) (...) {
// ...
if jdOrder.WxPayExpireAt != nil && gtime.Now().After(jdOrder.WxPayExpireAt) {
// 支付链接已过期,尝试刷新
newWxPayUrl, refreshErr := s.refreshPaymentUrl(ctx, jdOrder.JdOrderId, jdOrder.PayId, jdOrder.CookieId, orderId)
if refreshErr != nil {
// 刷新失败,标记旧订单为失效
_ = s.UpdateJdOrderStatus(ctx, jdOrder.JdOrderId, int(consts.JdOrderStatusExpired), "刷新支付链接失败")
_ = s.RecordJdOrderHistory(ctx, jdOrder.JdOrderId, string(consts.JdOrderChangeTypeInvalid), orderId, jdOrder.WxPayUrl)
_ = s.RecordCookieHistory(ctx, jdOrder.CookieId, string(consts.CookieChangeTypeRefreshFail), 0, 0, orderId, 0)
// 解绑旧京东订单
_ = s.updateJdOrderCurrentOrderId(ctx, jdOrder.JdOrderId, "")
// 创建新的京东订单(带重试机制)
newJdOrderId, newCookieId, newWxPayUrl, createErr := s.createNewJdOrderWithRetry(ctx, orderId, gconv.Float64(order.Amount), consts.RedeemOrderCardCategory(order.Category))
if createErr != nil {
return "", "", "", gerror.Wrap(createErr, "刷新失败且创建新订单失败")
}
// 更新订单关联的京东订单ID和支付链接
_ = s.updateOrderJdOrderId(ctx, orderId, newJdOrderId, newWxPayUrl)
// 更新京东订单的当前关联订单ID
_ = s.updateJdOrderCurrentOrderId(ctx, newJdOrderId, orderId)
// 记录Cookie使用历史
_ = s.RecordCookieHistory(ctx, newCookieId, string(consts.CookieChangeTypeUse), 0, 0, orderId, 0)
// 记录订单重新绑定历史
_ = s.RecordOrderHistory(ctx, orderId, string(consts.OrderChangeTypeRebind), newJdOrderId)
// 返回新的支付信息
jdOrderId = newJdOrderId
wxPayUrl = newWxPayUrl
} else {
// 刷新成功,更新支付链接
wxPayUrl = newWxPayUrl
_ = s.updateJdOrderPaymentUrl(ctx, jdOrderId, wxPayUrl)
}
}
// ...
}
改进点:
- ✅ 刷新失败时不直接返回错误
- ✅ 自动标记旧订单为失效
- ✅ 自动创建新的京东订单(带重试机制)
- ✅ 更新订单关联关系
- ✅ 记录完整的操作历史(符合变更记录规范)
- ✅ 提升用户体验,保证支付链接可用
新增辅助方法:
// updateOrderJdOrderId 更新订单关联的京东订单ID和支付链接
func (s *sJdCookie) updateOrderJdOrderId(ctx context.Context, orderId, jdOrderId, wxPayUrl string) error
历史记录:
- Cookie刷新失败历史
- 京东订单失效历史
- 京东订单解绑历史
- 新Cookie使用历史
- 订单重新绑定历史
3. 移除重试次数限制
文件:internal/logic/jd_cookie/order_create.go
变更前:
func (s *sJdCookie) createNewJdOrderWithRetry(...) (jdOrderId, cookieId, wxPayUrl string, err error) {
const maxRetryCount = 10 // 最大重试次数
var lastErr error
var triedCookies []string
for retryCount := range maxRetryCount {
// 获取可用的Cookie
availableCookieId, cookieErr := s.GetAvailableCookie(ctx)
if cookieErr != nil {
glog.Warning(ctx, "获取可用Cookie失败", g.Map{
"orderId": orderId,
"retryCount": retryCount,
"error": cookieErr,
})
lastErr = cookieErr
break
}
// ... 其他逻辑
glog.Info(ctx, "创建京东订单成功", g.Map{
"orderId": orderId,
"jdOrderId": jdOrderId,
"cookieId": availableCookieId,
"retryCount": retryCount,
})
return jdOrderId, availableCookieId, wxPayUrl, nil
}
// 所有重试都失败了
return "", "", "", gerror.Wrapf(lastErr, "创建京东订单失败,已尝试%d个Cookie", len(triedCookies))
}
变更后:
func (s *sJdCookie) createNewJdOrderWithRetry(...) (jdOrderId, cookieId, wxPayUrl string, err error) {
var lastErr error
var triedCookies []string // 记录已尝试的Cookie
// 不断尝试,直到没有Cookie为止
for {
// 获取可用的Cookie
availableCookieId, cookieErr := s.GetAvailableCookie(ctx)
if cookieErr != nil {
glog.Warning(ctx, "获取可用Cookie失败", g.Map{
"orderId": orderId,
"triedCookies": len(triedCookies),
"error": cookieErr,
})
lastErr = cookieErr
break // 没有可用Cookie,停止重试
}
// 检查是否已经尝试过这个Cookie
if s.hasCookieBeenTried(triedCookies, availableCookieId) {
continue
}
// 记录已尝试的Cookie
triedCookies = append(triedCookies, availableCookieId)
// ... 其他逻辑
glog.Info(ctx, "创建京东订单成功", g.Map{
"orderId": orderId,
"jdOrderId": jdOrderId,
"cookieId": availableCookieId,
"triedCookies": len(triedCookies),
})
return jdOrderId, availableCookieId, wxPayUrl, nil
}
// 所有Cookie都失败了
if lastErr == nil {
lastErr = gerror.New(consts.ErrCodeCookieNotAvailable)
}
glog.Error(ctx, "创建京东订单失败,所有Cookie均不可用", g.Map{
"orderId": orderId,
"triedCookies": triedCookies,
"error": lastErr,
})
return "", "", "", gerror.Wrapf(lastErr, "创建京东订单失败,已尝试%d个Cookie", len(triedCookies))
}
改进点:
- ✅ 移除
maxRetryCount = 10的限制(符合重试机制设计规范) - ✅ 使用
for无限循环,直到没有可用Cookie为止 - ✅ 日志中改用
triedCookies数量代替retryCount - ✅ 最大化利用所有可用Cookie
- ✅ 提升订单创建成功率
4. 解绑功能增强
文件:internal/logic/jd_cookie/order_utils.go
变更前:
func (s *sJdCookie) updateJdOrderCurrentOrderId(ctx context.Context, jdOrderId, orderId string) error {
// 查找订单ID对应的内部ID
var order *entity.V1JdCookieOrder
err := dao.V1JdCookieOrder.Ctx(ctx).DB(config.GetDatabaseV1()).
Where(dao.V1JdCookieOrder.Columns().OrderId, orderId).
Scan(&order)
if err != nil || order == nil {
return gerror.New("订单不存在")
}
// 更新京东订单的当前关联订单ID
_, err = m.Where(dao.V1JdCookieJdOrder.Columns().JdOrderId, jdOrderId).Update(&do.V1JdCookieJdOrder{
CurrentOrderId: order.Id,
})
// ...
}
变更后:
func (s *sJdCookie) updateJdOrderCurrentOrderId(ctx context.Context, jdOrderId, orderId string) error {
m := dao.V1JdCookieJdOrder.Ctx(ctx).DB(config.GetDatabaseV1())
// 如果orderId为空,表示解绑
if orderId == "" {
// 获取更新前的京东订单信息
var oldJdOrder *entity.V1JdCookieJdOrder
err := m.Where(dao.V1JdCookieJdOrder.Columns().JdOrderId, jdOrderId).Scan(&oldJdOrder)
// ...
// 解绑:设置为null
_, err = m.Where(dao.V1JdCookieJdOrder.Columns().JdOrderId, jdOrderId).Update(&do.V1JdCookieJdOrder{
CurrentOrderId: nil,
})
// 记录解绑历史
if oldJdOrder != nil && oldJdOrder.CurrentOrderId > 0 {
_ = s.RecordJdOrderHistory(ctx, jdOrderId, string(consts.JdOrderChangeTypeUnbind), "", oldJdOrder.WxPayUrl)
}
return nil
}
// 查找订单ID对应的内部ID(绑定操作)
// ...
}
改进点:
- ✅ 支持传入空字符串进行解绑操作
- ✅ 解绑时设置
CurrentOrderId为nil - ✅ 记录解绑历史(符合变更记录规范)
- ✅ 用于 GetPaymentUrl 刷新失败时解绑旧订单
📊 影响范围总结
修改的文件
| 文件 | 变更内容 | 行数变化 |
|---|---|---|
order_create.go |
1. 调用refreshPaymentUrl时传递orderId 2. 移除重试次数限制 |
+14/-14 |
order_query.go |
刷新失败时自动创建新订单 | +38/-7 |
order_utils.go |
1. refreshPaymentUrl添加orderId参数 2. 新增updateOrderJdOrderId方法 3. updateJdOrderCurrentOrderId支持解绑 |
+36/-1 |
新增方法
// updateOrderJdOrderId 更新订单关联的京东订单ID和支付链接
func (s *sJdCookie) updateOrderJdOrderId(ctx context.Context, orderId, jdOrderId, wxPayUrl string) error
方法签名变更
// 变更前
func (s *sJdCookie) refreshPaymentUrl(ctx context.Context, jdOrderId, payId, cookieId string) (wxPayUrl string, err error)
// 变更后
func (s *sJdCookie) refreshPaymentUrl(ctx context.Context, jdOrderId, payId, cookieId, orderId string) (wxPayUrl string, err error)
🧪 测试结果
=== RUN TestShouldExtractCard
--- PASS: TestShouldExtractCard (0.00s)
=== RUN TestBatchCheckPaymentStatusConfig
--- PASS: TestBatchCheckPaymentStatusConfig (0.00s)
=== RUN TestCacheKeyGeneration
--- PASS: TestCacheKeyGeneration (0.00s)
PASS
ok kami/internal/logic/jd_cookie 0.875s
✅ 所有测试通过!
go build -o /dev/null .
✅ 编译成功!
🎯 优势分析
1. 提升成功率
- 无限重试直到所有Cookie用完,最大化订单创建成功率
- GetPaymentUrl刷新失败自动降级,保证用户始终能获得有效支付链接
2. 完善追踪
- 刷新支付链接使用真实订单ID,便于日志追踪和问题定位
- 记录完整的操作历史(刷新失败、解绑、重新绑定等)
- 符合异常处理与记录规范和变更记录规范
3. 用户体验
- 刷新失败时用户无感知切换到新订单
- 减少订单创建失败的概率
4. 系统健壮性
- 自动处理异常情况,减少人工干预
- 完整的状态流转和历史记录
📝 使用场景
场景1:获取支付链接时刷新失败
流程:
1. 用户请求支付链接
2. 检测到支付链接已过期
3. 尝试刷新支付链接
4. 刷新失败
↓
5. 标记旧京东订单为失效
6. 解绑旧京东订单
7. 创建新京东订单(无限重试)
8. 更新订单关联
9. 返回新的支付链接
历史记录:
- 旧Cookie刷新失败
- 旧京东订单失效
- 旧京东订单解绑
- 新Cookie使用
- 订单重新绑定
场景2:创建订单时Cookie不断失败
流程:
1. 尝试Cookie 1 → 失败 → 暂停Cookie 1
2. 尝试Cookie 2 → 失败 → 暂停Cookie 2
3. 尝试Cookie 3 → 失败 → 暂停Cookie 3
...
N. 尝试Cookie N → 成功 ✓
日志示例:
[WARN] 京东下单失败,尝试切换Cookie重试 {"orderId":"ORDER123","cookieId":"COOKIE1","triedCookies":1}
[WARN] 京东下单失败,尝试切换Cookie重试 {"orderId":"ORDER123","cookieId":"COOKIE2","triedCookies":2}
[INFO] 创建京东订单成功 {"orderId":"ORDER123","jdOrderId":"JD789","cookieId":"COOKIE3","triedCookies":3}
⚠️ 注意事项
- 性能影响:无限重试可能导致响应时间较长,建议配合超时控制使用
- 并发控制:多个请求同时创建订单时,注意Cookie的并发分配
- 监控告警:建议添加监控,当尝试Cookie数量超过阈值时告警
📚 相关文档
更新时间:2025-10-11
更新内容:订单创建逻辑优化
测试状态:✅ 通过