feat(v2): gateway 经 Picker 路由选账户 + retry 换号(ExcludeAccounts);替换首个 enabled

This commit is contained in:
wangjia
2026-07-10 14:02:33 +08:00
parent 381288e707
commit c06f6d3a3c
7 changed files with 109 additions and 17 deletions
+25 -13
View File
@@ -37,15 +37,15 @@ type WebhookEnqueuer interface {
type Gateway struct {
orders *store.OrderStore
providers *provider.Registry
accounts *accounts.Registry
picker accounts.Picker
products ProductResolver
webhook WebhookEnqueuer
region string
}
func New(orders *store.OrderStore, providers *provider.Registry, accts *accounts.Registry,
func New(orders *store.OrderStore, providers *provider.Registry, picker accounts.Picker,
products ProductResolver, webhook WebhookEnqueuer, region string) *Gateway {
return &Gateway{orders: orders, providers: providers, accounts: accts,
return &Gateway{orders: orders, providers: providers, picker: picker,
products: products, webhook: webhook, region: region}
}
@@ -80,13 +80,17 @@ func (g *Gateway) CreateOrder(ctx context.Context, in CreateOrderInput) (*OrderR
if err != nil {
return nil, err // ErrUnknownMethod
}
accts := g.accounts.EnabledFor(in.Method, g.region)
if len(accts) == 0 {
return nil, ErrNoAccount
}
acct := accts[0] // 路由策略(round_robin/weighted/…)在 P5;P2 取首个 enabled。
outNo := util.NewOutTradeNo("pay")
acct, err := g.picker.Pick(in.Method, g.region, accounts.PickHint{
OutTradeNo: outNo, AmountMinor: amountMinor,
})
if err != nil {
if errors.Is(err, accounts.ErrNoAccount) {
return nil, ErrNoAccount
}
return nil, err
}
if err := g.orders.CreateOrder(&model.OrderV2{
OutTradeNo: outNo, BizSystem: in.BizSystem, BizRef: in.BizRef,
Subject: subject, AmountMinor: amountMinor, Currency: currency,
@@ -150,11 +154,19 @@ func (g *Gateway) RetryOrder(ctx context.Context, outTradeNo, method string) (*O
if err != nil {
return nil, err
}
accts := g.accounts.EnabledFor(method, g.region)
if len(accts) == 0 {
return nil, ErrNoAccount
tried, err := g.orders.AttemptAccountIDs(outTradeNo, method)
if err != nil {
return nil, err
}
acct, err := g.picker.Pick(method, g.region, accounts.PickHint{
OutTradeNo: outTradeNo, AmountMinor: o.AmountMinor, ExcludeAccounts: tried,
})
if err != nil {
if errors.Is(err, accounts.ErrNoAccount) {
return nil, ErrNoAccount
}
return nil, err
}
acct := accts[0]
if _, err := g.orders.ExpirePendingAttempts(outTradeNo); err != nil {
return nil, err