Estados do breaker
| closed | Tudo normal, as chamadas passam. Conta as falhas. |
| open | Estourou o limite de falhas. Fail fast: nem chama o downstream, devolve erro na hora. |
| half-open | Passou o cooldown. Deixa uma chamada de teste passar. Deu certo, fecha. Falhou, abre de novo. |
Quando NÃO retry
| 4xx | Erro do cliente. Vai falhar igual no retry. |
| não idempotente | Sem chave de idempotência, retry pode cobrar duas vezes (aula 36). |
Retry com backoff + jitter (Go)
func retry(fn func() error) error {
var err error
for n := 0; n < maxRetries; n++ {
if err = fn(); err == nil {
return nil
}
if !isTransient(err) {
return err // 4xx, não idempotente: para
}
base := time.Second * (1 << n) // 1s, 2s, 4s
jitter := time.Duration(rand.Int63n(int64(base)))
time.Sleep(base/2 + jitter) // espalha
}
return err
}
Circuit breaker (Go)
func (b *Breaker) Call(fn func() error) error {
if b.state == "open" {
if time.Now().Before(b.openUntil) {
return ErrOpen // fail fast, nem chama
}
b.state = "half" // testa se voltou
}
if err := fn(); err != nil {
b.fails++
if b.fails >= b.threshold {
b.state = "open"
b.openUntil = time.Now().Add(b.cooldown)
}
return err
}
b.fails, b.state = 0, "closed" // fechou
return nil
}