rproxy: circuit breaker for asks to waf (closes #392)
check / check (push) Successful in 5m31s
check / check (push) Successful in 5m31s
Five asks that get no answer in time within five seconds open the breaker. While open, a request takes SWW_RPROXY_WAF_BACKEND_NO_ANSWER_DISPOSITION without asking waf, except one ask a second; the first answer closes it. Slow answers count as failures. SPEC.md describes it. The sww test that stops and restarts waf now waits for the breaker to close before it expects the ban again. Model: opus-5-5
This commit is contained in:
1 parent
8efd6339a6
commit
969383894c
10 files changed
+391
-18
No files matched your search
@@ -15,6 +15,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -1395,6 +1396,62 @@ func TestSendsNoReportWithoutAnAnswer(t *testing.T) {
|
||||
standIn.wantNoReport(t)
|
||||
}
|
||||
|
||||
func TestFiveFailedAsksKeepTheNextRequestFromAskingWAF(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for name, failure := range map[string]http.HandlerFunc{
|
||||
"no answer at all": func(http.ResponseWriter, *http.Request) {
|
||||
panic(http.ErrAbortHandler)
|
||||
},
|
||||
"a slow answer": func(_ http.ResponseWriter, r *http.Request) {
|
||||
<-r.Context().Done()
|
||||
},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var answering atomic.Bool
|
||||
|
||||
standIn := startWAF(
|
||||
t,
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
if answering.Load() {
|
||||
allow(w, r)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
failure(w, r)
|
||||
},
|
||||
)
|
||||
app := startApp(t, greet)
|
||||
addr, out := startRProxy(
|
||||
t,
|
||||
standIn.URL,
|
||||
app.URL,
|
||||
map[string]string{
|
||||
wafBackendTimeout: "200",
|
||||
},
|
||||
)
|
||||
|
||||
for range 5 {
|
||||
wantGreeting(t, get(t, addr, "/"))
|
||||
standIn.question(t)
|
||||
}
|
||||
|
||||
answering.Store(true)
|
||||
wantGreeting(t, get(t, addr, "/"))
|
||||
out.waitFor(t, "the circuit breaker is open")
|
||||
|
||||
select {
|
||||
case <-standIn.questions:
|
||||
t.Error("waf was asked, want it not to be")
|
||||
case <-time.After(10 * pollInterval):
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPathUnderOwnPrefixNeverReachesTheApp(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in new issue
Block a user