Per-host circuit breaker с retry для CDN fetch и RIPEstat; порог 5 ошибок, cooldown 30s. Co-authored-by: Cursor <[email protected]>
35 lines
875 B
Go
35 lines
875 B
Go
package httpclient
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestDoWithBreaker_opensAfterFailures(t *testing.T) {
|
|
ResetHostBreakers()
|
|
var calls atomic.Int32
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
calls.Add(1)
|
|
http.Error(w, "fail", http.StatusBadGateway)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
hc := New(5 * time.Second)
|
|
for i := 0; i < defaultBreakerThreshold*3; i++ {
|
|
req, _ := http.NewRequest(http.MethodGet, srv.URL, nil)
|
|
_, _ = DoWithBreaker(context.Background(), hc, req, 1)
|
|
}
|
|
req, _ := http.NewRequest(http.MethodGet, srv.URL, nil)
|
|
_, err := DoWithBreaker(context.Background(), hc, req, 1)
|
|
if err == nil || err.Error() == "" {
|
|
t.Fatal("expected circuit open error")
|
|
}
|
|
if got := calls.Load(); got == 0 {
|
|
t.Fatal("expected at least one upstream call")
|
|
}
|
|
}
|