2026-04-29 12:43:05 +08:00

89 lines
3.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package user
import (
"context"
"log"
"strings"
"time"
userdomain "hyapp/services/user-service/internal/domain/user"
)
const (
defaultRegionRebuildPollInterval = 5 * time.Second
defaultRegionRebuildLockTTL = 30 * time.Second
defaultRegionRebuildBatchSize = 500
)
// RegionRebuildWorkerOptions 控制 user_region_rebuild_tasks 的后台消费节奏。
type RegionRebuildWorkerOptions struct {
// WorkerID 写入 task locked_by便于排查某个节点是否卡住任务。
WorkerID string
// PollInterval 是没有任务或单轮处理后下一次扫描的间隔。
PollInterval time.Duration
// 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.PollInterval <= 0 {
options.PollInterval = defaultRegionRebuildPollInterval
}
if options.LockTTL <= 0 {
options.LockTTL = defaultRegionRebuildLockTTL
}
if options.BatchSize <= 0 {
options.BatchSize = defaultRegionRebuildBatchSize
}
return options
}
// RunRegionRebuildWorker 持续消费 user_region_rebuild_tasks保证管理端映射变更最终刷新历史用户快照。
func (s *Service) RunRegionRebuildWorker(ctx context.Context, options RegionRebuildWorkerOptions) {
options = normalizeRegionRebuildWorkerOptions(options)
if s.regionRebuildRepository == nil {
log.Printf("worker=user_region_rebuild status=stopped reason=%q", "repository is not configured")
return
}
_, _ = s.ProcessNextRegionRebuildTask(ctx, options)
ticker := time.NewTicker(options.PollInterval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
_, _ = s.ProcessNextRegionRebuildTask(ctx, options)
}
}
}
// ProcessNextRegionRebuildTask 处理一个待重算任务错误只影响本轮worker 下一轮继续扫描。
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 {
log.Printf("worker=user_region_rebuild worker_id=%s status=failed error=%q", options.WorkerID, err.Error())
return result, err
}
if result.NoTask {
return result, nil
}
log.Printf("worker=user_region_rebuild worker_id=%s task_id=%d country=%s target_region_id=%d status=%s processed_users=%d cursor_user_id=%d", options.WorkerID, result.TaskID, result.CountryCode, result.TargetRegionID, result.Status, result.ProcessedUsers, result.CursorUserID)
return result, nil
}