package user import ( "context" "log/slog" "strings" "time" "hyapp/pkg/logx" userdomain "hyapp/services/user-service/internal/domain/user" ) const ( defaultRegionRebuildLockTTL = 30 * time.Second defaultRegionRebuildBatchSize = 500 ) // RegionRebuildWorkerOptions 控制 cron-service 触发的单批 user_region_rebuild_tasks 处理边界。 type RegionRebuildWorkerOptions struct { // WorkerID 写入 task locked_by,便于排查某个节点是否卡住任务。 WorkerID string // LockTTL 是单个 task claim 后允许本节点持有的最长时间,过期可被其他节点接管。 LockTTL time.Duration // BatchSize 是单次最多更新的 users 数量,避免大国家全量更新长事务。 BatchSize int } func normalizeRegionRebuildWorkerOptions(options RegionRebuildWorkerOptions) RegionRebuildWorkerOptions { options.WorkerID = strings.TrimSpace(options.WorkerID) if options.WorkerID == "" { options.WorkerID = "user-region-rebuild" } if options.LockTTL <= 0 { options.LockTTL = defaultRegionRebuildLockTTL } if options.BatchSize <= 0 { options.BatchSize = defaultRegionRebuildBatchSize } return options } // ProcessNextRegionRebuildTask 处理一个待重算任务;错误只影响本批,cron-service 下一轮继续触发。 func (s *Service) ProcessNextRegionRebuildTask(ctx context.Context, options RegionRebuildWorkerOptions) (userdomain.RegionRebuildProcessResult, error) { options = normalizeRegionRebuildWorkerOptions(options) if s.regionRebuildRepository == nil { return userdomain.RegionRebuildProcessResult{NoTask: true}, nil } result, err := s.regionRebuildRepository.ProcessNextRegionRebuildTask(ctx, options.WorkerID, s.now().UnixMilli(), options.LockTTL, options.BatchSize) if err != nil { logx.Error(ctx, "worker_batch_failed", err, slog.String("worker", "user_region_rebuild"), slog.String("worker_id", options.WorkerID), slog.Int("batch_size", options.BatchSize)) return result, err } if result.NoTask { return result, nil } logx.Info(ctx, "worker_batch_processed", slog.String("worker", "user_region_rebuild"), slog.String("worker_id", options.WorkerID), slog.Int64("task_id", result.TaskID), slog.String("country", result.CountryCode), slog.Int64("target_region_id", result.TargetRegionID), slog.String("status", result.Status), slog.Int("processed_users", result.ProcessedUsers), slog.Int64("cursor_user_id", result.CursorUserID), ) return result, nil }