package task import ( "context" "sync" "time" "go.uber.org/zap" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/pkg/constants" ) // SetIngest 注入入库消息发布器与入库模式读取(受控系统配置 polling.ingest.mode,数秒内生效)。 func (b *PollingBase) SetIngest(publisher *IngestPublisher, async func(ctx context.Context) bool) { b.ingest = publisher b.ingestAsync = async } // publishIngest 在异步入库模式下发布入库消息,返回是否已发布;返回 false 时调用方按原逻辑同步入库。 // 本轮同时是优先执行时保持同步入库:加急结果需在本轮写库后才能完成优先项。 func (b *PollingBase) publishIngest(ctx context.Context, round *pollingPriorityRound, msg IngestMessage) bool { if round != nil || b.ingest == nil || b.ingestAsync == nil || !b.ingestAsync(ctx) { return false } if err := b.ingest.PublishIngest(ctx, msg); err != nil { b.logger.Warn("发布入库消息失败,本次改为同步入库", zap.String("kind", msg.Kind), zap.Uint("card_id", msg.CardID), zap.String("observation_id", msg.ObservationID), zap.Error(err)) return false } return true } // scopeCache 是卡轮询范围校验结果的进程内短缓存,只供按运营商账户调度的卡任务使用,减少每个卡任务查绑定与设备。 // 设备停用轮询最迟在缓存时长后生效;生命周期事件仍按实时校验移出队列。 type scopeCache struct { mu sync.Mutex entries map[uint]scopeEntry } type scopeEntry struct { allowed bool loadedAt time.Time } // scopeAllowsCached 返回卡是否在轮询范围内(卡自身开关实时判断,设备开关按短缓存)。 func (b *PollingBase) scopeAllowsCached(ctx context.Context, card *model.IotCard) bool { if !card.EnablePolling { return false } if b.scopeChecker == nil || card.IsStandalone { return true } b.scopeCache.mu.Lock() entry, ok := b.scopeCache.entries[card.ID] b.scopeCache.mu.Unlock() if ok && time.Since(entry.loadedAt) < constants.PollingScopeCacheTTL { return entry.allowed } allowed := b.scopeChecker.ShouldEnqueue(ctx, card) b.scopeCache.mu.Lock() if b.scopeCache.entries == nil || len(b.scopeCache.entries) > 200000 { b.scopeCache.entries = map[uint]scopeEntry{} } b.scopeCache.entries[card.ID] = scopeEntry{allowed: allowed, loadedAt: time.Now()} b.scopeCache.mu.Unlock() return allowed } // resetDayCache 是运营商账户流量重置日的进程内缓存。 type resetDayCache struct { mu sync.Mutex entries map[uint]resetDayEntry } type resetDayEntry struct { day int loadedAt time.Time } // carrierResetDay 返回运营商账户流量重置日(1-28),成功读取的值按 1 分钟缓存;读取失败或未配置时返回 1 且不缓存。 func (b *PollingBase) carrierResetDay(ctx context.Context, carrierID uint) int { b.resetDays.mu.Lock() entry, ok := b.resetDays.entries[carrierID] b.resetDays.mu.Unlock() if ok && time.Since(entry.loadedAt) < constants.PollingCarrierResetDayCacheTTL { return entry.day } if b.db == nil { return 1 } var days []int if err := b.db.WithContext(ctx).Unscoped().Model(&model.Carrier{}).Where("id = ?", carrierID).Limit(1). Pluck("data_reset_day", &days).Error; err != nil || len(days) == 0 || days[0] == 0 { return 1 } b.resetDays.mu.Lock() if b.resetDays.entries == nil { b.resetDays.entries = map[uint]resetDayEntry{} } b.resetDays.entries[carrierID] = resetDayEntry{day: days[0], loadedAt: time.Now()} b.resetDays.mu.Unlock() return days[0] }