补齐相关日志日志
This commit is contained in:
@@ -41,10 +41,19 @@ func runBenefitCompensation() {
|
||||
lockKey := "ztcloset:lock:benefit:compensation"
|
||||
lockVal := genUUID()
|
||||
ok, lerr := redisdao.TryLock(ctx, lockKey, lockVal, time.Minute)
|
||||
if lerr != nil || !ok {
|
||||
if lerr != nil {
|
||||
slog.ErrorContext(ctx, "benefit compensation: acquire lock failed", "error", lerr)
|
||||
return
|
||||
}
|
||||
defer redisdao.Unlock(context.Background(), lockKey, lockVal)
|
||||
if !ok {
|
||||
slog.DebugContext(ctx, "benefit compensation: another instance running, skip")
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if uerr := redisdao.Unlock(context.Background(), lockKey, lockVal); uerr != nil {
|
||||
slog.WarnContext(ctx, "benefit compensation: release lock failed", "error", uerr)
|
||||
}
|
||||
}()
|
||||
|
||||
taskDao := mysqldao.NewBenefitGrantTaskDao()
|
||||
s := NewOrderService()
|
||||
@@ -58,7 +67,12 @@ func runBenefitCompensation() {
|
||||
}
|
||||
|
||||
// 恢复超时的「发放中」任务(认领后崩溃的场景),使其回到待发放继续重试。
|
||||
_, _ = taskDao.BenefitGrantTaskRecoverStale(ctx, nowUnix()-int64((10*time.Minute).Seconds()))
|
||||
recovered, rerr := taskDao.BenefitGrantTaskRecoverStale(ctx, nowUnix()-int64((10*time.Minute).Seconds()))
|
||||
if rerr != nil {
|
||||
slog.ErrorContext(ctx, "benefit compensation: recover stale grant tasks failed", "error", rerr)
|
||||
} else if recovered > 0 {
|
||||
slog.InfoContext(ctx, "benefit compensation: recovered stale grant tasks", "count", recovered)
|
||||
}
|
||||
|
||||
tasks, err := taskDao.BenefitGrantTaskListPending(ctx, 100)
|
||||
if err != nil {
|
||||
@@ -70,7 +84,9 @@ func runBenefitCompensation() {
|
||||
}
|
||||
|
||||
revokeDao := mysqldao.NewBenefitRevokeTaskDao()
|
||||
_ = revokeDao.RecoverStale(ctx, nowUnix()-int64((10*time.Minute).Seconds()))
|
||||
if rerr := revokeDao.RecoverStale(ctx, nowUnix()-int64((10*time.Minute).Seconds())); rerr != nil {
|
||||
slog.ErrorContext(ctx, "benefit compensation: recover stale revoke tasks failed", "error", rerr)
|
||||
}
|
||||
if revokeTasks, err := revokeDao.ListPending(ctx, 100); err == nil {
|
||||
for i := range revokeTasks {
|
||||
s.executeRevokeTask(ctx, &revokeTasks[i])
|
||||
@@ -86,7 +102,10 @@ func (s *OrderService) retryBenefitTask(ctx context.Context, task *mysqlmodel.Be
|
||||
|
||||
// 重试次数超限,标记失败并告警,等待人工介入。
|
||||
if task.RetryCount >= task.MaxRetry {
|
||||
_ = taskDao.BenefitGrantTaskUpdateByID(ctx, task.ID, map[string]any{"status": BenefitTaskFailed})
|
||||
if uerr := taskDao.BenefitGrantTaskUpdateByID(ctx, task.ID, map[string]any{"status": BenefitTaskFailed}); uerr != nil {
|
||||
slog.ErrorContext(ctx, "benefit compensation: mark exhausted task failed status failed",
|
||||
"order_no", task.OrderNo, "benefit_type", task.BenefitType, "error", uerr)
|
||||
}
|
||||
slog.ErrorContext(ctx, "benefit grant task exhausted retries",
|
||||
"order_no", task.OrderNo, "benefit_type", task.BenefitType, "retry_count", task.RetryCount)
|
||||
return
|
||||
@@ -94,7 +113,12 @@ func (s *OrderService) retryBenefitTask(ctx context.Context, task *mysqlmodel.Be
|
||||
|
||||
// 幂等判断:若发放流水已存在(上次发放成功但未置 success 的崩溃窗口),直接置成功。
|
||||
if granted, err := s.benefitAlreadyGranted(ctx, task); err == nil && granted {
|
||||
_ = taskDao.BenefitGrantTaskUpdateByID(ctx, task.ID, map[string]any{"status": BenefitTaskSuccess})
|
||||
if uerr := taskDao.BenefitGrantTaskUpdateByID(ctx, task.ID, map[string]any{"status": BenefitTaskSuccess}); uerr != nil {
|
||||
slog.ErrorContext(ctx, "benefit compensation: mark already-granted task success failed",
|
||||
"order_no", task.OrderNo, "benefit_type", task.BenefitType, "error", uerr)
|
||||
}
|
||||
slog.InfoContext(ctx, "benefit already granted, task marked success",
|
||||
"order_no", task.OrderNo, "benefit_type", task.BenefitType)
|
||||
return
|
||||
} else if err != nil {
|
||||
slog.ErrorContext(ctx, "check benefit granted failed",
|
||||
@@ -128,9 +152,14 @@ func (s *OrderService) benefitAlreadyGranted(ctx context.Context, task *mysqlmod
|
||||
|
||||
func (s *OrderService) executeRevokeTaskByOrder(ctx context.Context, orderNo string) {
|
||||
task, err := mysqldao.NewBenefitRevokeTaskDao().GetByOrderNo(ctx, orderNo)
|
||||
if err == nil {
|
||||
s.executeRevokeTask(ctx, task)
|
||||
if err != nil {
|
||||
if isNotFound(err) {
|
||||
return // 无回收任务(如未退款订单),属正常路径。
|
||||
}
|
||||
slog.ErrorContext(ctx, "get benefit revoke task failed", "order_no", orderNo, "error", err)
|
||||
return
|
||||
}
|
||||
s.executeRevokeTask(ctx, task)
|
||||
}
|
||||
|
||||
func (s *OrderService) executeRevokeTask(ctx context.Context, task *mysqlmodel.BenefitRevokeTask) {
|
||||
@@ -142,17 +171,30 @@ func (s *OrderService) executeRevokeTask(ctx context.Context, task *mysqlmodel.B
|
||||
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)
|
||||
slog.ErrorContext(ctx, "claim benefit revoke task failed", "order_no", task.OrderNo, "error", err)
|
||||
return
|
||||
}
|
||||
_ = dao.Update(ctx, task.ID, map[string]any{"status": BenefitTaskSuccess, "last_error": ""})
|
||||
if !claimed {
|
||||
slog.DebugContext(ctx, "benefit revoke task already claimed, skip", "order_no", task.OrderNo)
|
||||
return
|
||||
}
|
||||
order, oerr := s.orderDao.OrderGetByOrderNo(ctx, task.OrderNo)
|
||||
if oerr != nil {
|
||||
_ = dao.Update(ctx, task.ID, map[string]any{"status": BenefitTaskPending, "retry_count": gorm.Expr("retry_count + 1"), "last_error": oerr.Error()})
|
||||
slog.ErrorContext(ctx, "revoke refunded order benefits failed: get order failed",
|
||||
"order_no", task.OrderNo, "retry_count", task.RetryCount, "error", oerr)
|
||||
return
|
||||
}
|
||||
if rerr := s.revokeOrderBenefits(ctx, order); rerr != nil {
|
||||
_ = dao.Update(ctx, task.ID, map[string]any{"status": BenefitTaskPending, "retry_count": gorm.Expr("retry_count + 1"), "last_error": rerr.Error()})
|
||||
slog.ErrorContext(ctx, "revoke refunded order benefits failed",
|
||||
"order_no", task.OrderNo, "retry_count", task.RetryCount, "error", rerr)
|
||||
return
|
||||
}
|
||||
if uerr := dao.Update(ctx, task.ID, map[string]any{"status": BenefitTaskSuccess, "last_error": ""}); uerr != nil {
|
||||
slog.ErrorContext(ctx, "mark benefit revoke task success failed", "order_no", task.OrderNo, "error", uerr)
|
||||
return
|
||||
}
|
||||
slog.InfoContext(ctx, "refunded order benefits revoked", "order_no", task.OrderNo, "user_id", order.UserID)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user