补齐相关日志日志

This commit is contained in:
2026-09-16 00:23:49 +08:00
parent 8c2ea84939
commit b2e5eef3c8
39 changed files with 1576 additions and 176 deletions
+60 -18
View File
@@ -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)
}