package auth import ( "context" "fmt" "sync" "time" ) type Pool struct { creds []*Credential cursor int mu sync.Mutex } func NewPool(creds []*Credential) *Pool { return &Pool{creds: creds} } func (p *Pool) Pick() (*Credential, error) { p.mu.Lock() defer p.mu.Unlock() n := len(p.creds) if n == 0 { return nil, fmt.Errorf("no credentials available") } for i := 0; i < n; i++ { idx := (p.cursor + i) % n cred := p.creds[idx] if !cred.IsOnCooldown() { p.cursor = (idx + 1) % n return cred, nil } } return nil, fmt.Errorf("all %d credentials are on cooldown", n) } func (p *Pool) MarkFailure(cred *Credential, statusCode int) { switch { case statusCode == 429: cred.SetCooldown(30 * time.Second) case statusCode >= 500: cred.SetCooldown(5 * time.Second) } } func (p *Pool) MarkSuccess(cred *Credential) { cred.mu.Lock() defer cred.mu.Unlock() cred.CooldownUntil = time.Time{} } func (p *Pool) RefreshExpiring(ctx context.Context) { refreshAll(p) }