// Package prioritypolling 定义卡轮询优先队列的应用层契约。 // // 本包只承载业务事实的形状与执行语义,不依赖 Fiber、GORM、Redis、Asynq 或具体外部 SDK; // Outbox 写入、消费者展开与执行接缝适配分别位于基础设施与任务层。 package prioritypolling import ( "context" "time" "gorm.io/gorm" ) // PriorityRequestedEvent 是业务成功边界可靠请求「为该资源的卡建立优先轮询项」的事实。 // // 载荷沿用既有业务观测事件的形状(资源类型 / 资源 ID / 资源 ID 列表),并在业务事务内冻结卡快照: // 独立卡为自身(ResourceIDs 为空),绑定设备的资产为绑定状态有效的全部在用卡(写入 ResourceIDs)。 // TriggerType 取值与 pkg/constants.PollingPriorityTrigger* 一致;本轮要逐类型建项的任务类型集合 // 由代码常量给出(pkg/constants.PollingPriorityTaskTypes),不由事件载荷决定,避免同一决策出现两个权威。 // 来源订单与来源套餐使用记录只保存 ID,由消费者与读侧显式查询。 type PriorityRequestedEvent struct { EventID string `json:"event_id"` ResourceType string `json:"resource_type"` ResourceID uint `json:"resource_id"` ResourceIDs []uint `json:"resource_ids,omitempty"` TriggerType string `json:"trigger_type"` SourceOrderID uint `json:"source_order_id,omitempty"` SourcePackageUsageID uint `json:"source_package_usage_id,omitempty"` OccurredAt time.Time `json:"occurred_at"` RequestID string `json:"request_id,omitempty"` CorrelationID string `json:"correlation_id,omitempty"` } // PromptPublisher 把优先执行提示下发到既有轮询提示通道。 // // 提示通道不是权威:丢失或缓存服务重启时库内活动优先项仍在,后续普通轮询执行按条件认领仍会执行, // 只退化为延迟一个普通轮询周期;调用方不得以提示的下发成功作为入队事实成立的条件。 type PromptPublisher interface { EnqueuePriority(ctx context.Context, cardID uint, taskType string) error } // PriorityEventWriter 在原业务事务中追加优先轮询请求事件。 type PriorityEventWriter interface { AppendPriorityRequested(ctx context.Context, tx *gorm.DB, event PriorityRequestedEvent) error } type pollingPriorityTriggerKey struct{} // WithPollingPriorityTrigger 标记本次业务评估来自普通套餐轮询。 // // 「资产无有效套餐」这一场景在停复机评估内部判定,而该评估入口被观测消费者、手动实名、保护期轮询、 // 既有兼容入口等多条调用链复用;只有普通套餐轮询来源才允许追加优先轮询请求, // 否则会在观测序列、手动实名、保护期与退款等上下文凭空产生加急触发。 func WithPollingPriorityTrigger(ctx context.Context) context.Context { return context.WithValue(ctx, pollingPriorityTriggerKey{}, true) } // IsPollingPriorityTrigger 判断当前业务评估是否来自普通套餐轮询。 func IsPollingPriorityTrigger(ctx context.Context) bool { value, _ := ctx.Value(pollingPriorityTriggerKey{}).(bool) return value }