keyPoolError returns an Error summarizing why no key is currently available. When at least one key is temporary, the smallest remaining cooldown is used as the retry-after.
()
| 205 | // temporary, the smallest remaining cooldown is used as the |
| 206 | // retry-after. |
| 207 | func (p *Pool) keyPoolError() *Error { |
| 208 | var retryAfter time.Duration |
| 209 | var hasCooldown bool |
| 210 | for i := range p.keys { |
| 211 | state, cooldown := p.keys[i].stateAndCooldown() |
| 212 | switch state { |
| 213 | // Recoverable now: a key's cooldown expired between the walker's |
| 214 | // check and this scan. Return Retry-After: 0 to indicate that |
| 215 | // an immediate retry will succeed. |
| 216 | case KeyStateValid: |
| 217 | return &Error{Kind: ErrorKindRateLimited} |
| 218 | // Recoverable later: track soonest remaining cooldown. |
| 219 | case KeyStateTemporary: |
| 220 | if !hasCooldown || cooldown < retryAfter { |
| 221 | retryAfter = cooldown |
| 222 | hasCooldown = true |
| 223 | } |
| 224 | // Permanent: keep walking to confirm error type. |
| 225 | default: |
| 226 | } |
| 227 | } |
| 228 | if hasCooldown { |
| 229 | return &Error{Kind: ErrorKindRateLimited, RetryAfter: retryAfter} |
| 230 | } |
| 231 | return &Error{Kind: ErrorKindPermanent} |
| 232 | } |
| 233 | |
| 234 | // PoolState returns a snapshot of each key's state in the pool's |
| 235 | // original order, used by tests and other diagnostic callers. Use |