package accounts import ( "hash/fnv" "github.com/wangjia/pay/config" ) // Weighted 按 Weight 加权选账户,决策源为 hash(OutTradeNo)(确定性、可复现、跨节点一致, // 见计划 D1)。Weight<=0 记 1(对齐 model.Account gorm default:1)。retry 换号由 // Router 的 ExcludeAccounts 过滤驱动,不依赖随机。 type Weighted struct{} func NewWeighted() *Weighted { return &Weighted{} } func (Weighted) Pick(_ string, candidates []config.AccountConfig, hint PickHint) (config.AccountConfig, error) { if len(candidates) == 0 { return config.AccountConfig{}, ErrNoAccount } if hint.OutTradeNo == "" { return candidates[0], nil } var total uint32 for _, c := range candidates { total += weightOf(c) } if total == 0 { // 理论不达(weightOf>=1),兜底 return candidates[0], nil } h := fnv.New32a() _, _ = h.Write([]byte(hint.OutTradeNo)) target := h.Sum32() % total var acc uint32 for _, c := range candidates { acc += weightOf(c) if target < acc { return c, nil } } return candidates[len(candidates)-1], nil // 浮点无关的整数走位,兜底不达 } func weightOf(c config.AccountConfig) uint32 { if c.Weight <= 0 { return 1 } return uint32(c.Weight) }