gpt
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/mysqldao"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/mysqlmodel"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/redisdao"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// StartBenefitCompensationScheduler 启动权益发放补偿定时任务:周期性重试发放失败的权益。
|
||||
@@ -46,6 +47,15 @@ func runBenefitCompensation() {
|
||||
defer redisdao.Unlock(context.Background(), lockKey, lockVal)
|
||||
|
||||
taskDao := mysqldao.NewBenefitGrantTaskDao()
|
||||
s := NewOrderService()
|
||||
// 对账已支付但任务未完整落库的订单,覆盖支付状态提交后进程崩溃/数据库瞬时错误。
|
||||
if orders, err := mysqldao.NewOrderDao().OrderListPaidMissingBenefitTasks(ctx, 100); err == nil {
|
||||
for i := range orders {
|
||||
s.grantOrderBenefits(ctx, &orders[i])
|
||||
}
|
||||
} else {
|
||||
slog.ErrorContext(ctx, "reconcile paid order benefits failed", "error", err)
|
||||
}
|
||||
|
||||
// 恢复超时的「发放中」任务(认领后崩溃的场景),使其回到待发放继续重试。
|
||||
_, _ = taskDao.BenefitGrantTaskRecoverStale(ctx, nowUnix()-int64((10*time.Minute).Seconds()))
|
||||
@@ -55,14 +65,19 @@ func runBenefitCompensation() {
|
||||
slog.ErrorContext(ctx, "list pending benefit tasks failed", "error", err)
|
||||
return
|
||||
}
|
||||
if len(tasks) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
s := NewOrderService()
|
||||
for i := range tasks {
|
||||
s.retryBenefitTask(ctx, &tasks[i])
|
||||
}
|
||||
|
||||
revokeDao := mysqldao.NewBenefitRevokeTaskDao()
|
||||
_ = revokeDao.RecoverStale(ctx, nowUnix()-int64((10*time.Minute).Seconds()))
|
||||
if revokeTasks, err := revokeDao.ListPending(ctx, 100); err == nil {
|
||||
for i := range revokeTasks {
|
||||
s.executeRevokeTask(ctx, &revokeTasks[i])
|
||||
}
|
||||
} else {
|
||||
slog.ErrorContext(ctx, "list pending benefit revoke tasks failed", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
// retryBenefitTask 重试单个补偿任务(幂等:先查发放流水避免重复发放)。
|
||||
@@ -110,3 +125,34 @@ func (s *OrderService) benefitAlreadyGranted(ctx context.Context, task *mysqlmod
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *OrderService) executeRevokeTaskByOrder(ctx context.Context, orderNo string) {
|
||||
task, err := mysqldao.NewBenefitRevokeTaskDao().GetByOrderNo(ctx, orderNo)
|
||||
if err == nil {
|
||||
s.executeRevokeTask(ctx, task)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *OrderService) executeRevokeTask(ctx context.Context, task *mysqlmodel.BenefitRevokeTask) {
|
||||
dao := mysqldao.NewBenefitRevokeTaskDao()
|
||||
if task.Status == BenefitTaskSuccess {
|
||||
return
|
||||
}
|
||||
if task.RetryCount >= task.MaxRetry {
|
||||
slog.ErrorContext(ctx, "benefit revoke task exceeded normal retry threshold; continuing for eventual consistency", "order_no", task.OrderNo, "retry_count", task.RetryCount)
|
||||
}
|
||||
claimed, err := dao.Claim(ctx, task.ID)
|
||||
if err != nil || !claimed {
|
||||
return
|
||||
}
|
||||
order, err := s.orderDao.OrderGetByOrderNo(ctx, task.OrderNo)
|
||||
if err == nil {
|
||||
err = s.revokeOrderBenefits(ctx, order)
|
||||
}
|
||||
if err != nil {
|
||||
_ = dao.Update(ctx, task.ID, map[string]any{"status": BenefitTaskPending, "retry_count": gorm.Expr("retry_count + 1"), "last_error": err.Error()})
|
||||
slog.ErrorContext(ctx, "revoke refunded order benefits failed", "order_no", task.OrderNo, "error", err)
|
||||
return
|
||||
}
|
||||
_ = dao.Update(ctx, task.ID, map[string]any{"status": BenefitTaskSuccess, "last_error": ""})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user