package task import ( "context" "time" "github.com/hibiken/asynq" "go.uber.org/zap" pollingSvc "github.com/break/junhong_cmp_fiber/internal/service/polling" "github.com/break/junhong_cmp_fiber/pkg/auditcontext" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" ) // PollingPriorityExpiryHandler 执行优先轮询项有效期到期处理任务。 // // 该任务只做一件事:把超过固定有效期仍未完成的优先项转已过期终态并出队。 // 到期判定与查询、读侧完全解耦,读接口 MUST NOT 隐式触发过期处理; // 本轮扫描未处理完的剩余项由下一轮计划任务继续,任务可重复执行。 type PollingPriorityExpiryHandler struct { service *pollingSvc.PriorityExpiryService logger *zap.Logger } // NewPollingPriorityExpiryHandler 创建优先轮询项有效期到期处理任务处理器。 func NewPollingPriorityExpiryHandler(service *pollingSvc.PriorityExpiryService, logger *zap.Logger) *PollingPriorityExpiryHandler { if logger == nil { logger = zap.NewNop() } return &PollingPriorityExpiryHandler{service: service, logger: logger} } // Handle 执行一次有效期到期扫描。 // 审计上下文固定为计划任务来源,与审计注册表中该动作允许的操作者与来源一致。 func (h *PollingPriorityExpiryHandler) Handle(ctx context.Context, task *asynq.Task) error { if h == nil || h.service == nil { return errors.New(errors.CodeServiceUnavailable, "优先轮询项有效期到期处理任务未配置") } taskType := constants.TaskTypePollingPriorityExpiry if task != nil && task.Type() != "" { taskType = task.Type() } ctx = auditcontext.With(ctx, auditcontext.Context{ ActorKind: constants.AuditActorScheduledJob, ActorID: taskType, ActorName: "优先轮询项有效期到期处理计划任务", Source: constants.AuditSourceScheduler, }) expiredCount, err := h.service.ExpireOverdue(ctx, time.Now().UTC()) if err != nil { h.logger.Error("优先轮询项有效期到期处理失败", zap.Error(err)) return err } if expiredCount > 0 { h.logger.Info("优先轮询项有效期到期处理完成", zap.Int("expired_count", expiredCount)) } return nil }