From: Willy Tarreau Date: Mon, 21 Sep 2026 20:47:03 +0000 (+0000) Subject: REGTESTS: proxy: test the connection retries, retry-on and redispatch X-Git-Tag: v3.5-dev8~53 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=7711d03f372fb3943e680b47890d5f1c33c0e0ec;p=haproxy.git REGTESTS: proxy: test the connection retries, retry-on and redispatch "retry-on" and "option redispatch" had no coverage, and the txn.conn_retries and txn.redispatched fetches which report their effect were not covered either. Three backends are used: one whose only server is unreachable, which must report as many retries as configured before giving up with a 503, one which redispatches the retry to a healthy server, and one which retries at the HTTP layer because the first server answers with a status listed in "retry-on". The connect timeout of the two backends which fail to connect is shortened since haproxy spreads the retries over it, which would otherwise make the test last as long as the default timeout. --- diff --git a/reg-tests/proxy/retry_on.vtc b/reg-tests/proxy/retry_on.vtc new file mode 100644 index 000000000..b035e92f4 --- /dev/null +++ b/reg-tests/proxy/retry_on.vtc @@ -0,0 +1,106 @@ +varnishtest "Test the connection retries, retry-on and option redispatch" + +# "retry-on" and "option redispatch" had no coverage, and the +# txn.conn_retries and txn.redispatched fetches which report their +# effect were not covered either. +# +# Three backends are used: one whose only server is unreachable, one +# which redispatches to a healthy server after the first attempt fails, +# and one which retries at the HTTP layer when the server answers with a +# 503. + +feature ignore_unknown_macro + +server s1 { + rxreq + txresp +} -start + +server s2 { + rxreq + txresp -status 503 +} -start + +server s3 { + rxreq + txresp -hdr "x-second: yes" +} -start + +haproxy h1 -conf { + global + .if feature(THREAD) + thread-groups 1 + .endif + chroot / + + defaults + mode http + timeout connect "${HAPROXY_TEST_TIMEOUT-5s}" + timeout client "${HAPROXY_TEST_TIMEOUT-5s}" + timeout server "${HAPROXY_TEST_TIMEOUT-5s}" + + frontend fe + bind "fd@${fe}" + use_backend redisp if { path /redisp } + use_backend l7 if { path /l7 } + default_backend dead + + http-after-response set-header x-retries "%[txn.conn_retries]" + http-after-response set-header x-redisp "%[txn.redispatched]" + + # every attempt fails, the client ends up with a 503. The connect + # timeout is shortened because haproxy spreads the retries over it. + backend dead + timeout connect 200ms + retries 2 + server s1 ${bad_backend} + + # the first server always fails, the retry is redispatched to the + # second one thanks to "option redispatch" + backend redisp + timeout connect 200ms + balance first + retries 1 + option redispatch + server bad ${bad_backend} + server good ${s1_addr}:${s1_port} + + # the first server answers, but with a status listed in "retry-on", + # so the request is retried and redispatched to the second one + backend l7 + balance first + retries 1 + retry-on 503 + option redispatch + server bad ${s2_addr}:${s2_port} + server good ${s3_addr}:${s3_port} +} -start + +client c1 -connect ${h1_fe_sock} { + # 1 initial attempt + 2 retries, all failed + txreq -url "/dead" + rxresp + expect resp.status == 503 + expect resp.http.x-retries == "2" + expect resp.http.x-redisp == "0" +} -run + +client c2 -connect ${h1_fe_sock} { + # the retry went to the other server + txreq -url "/redisp" + rxresp + expect resp.status == 200 + expect resp.http.x-retries == "1" + expect resp.http.x-redisp == "1" +} -run + +client c3 -connect ${h1_fe_sock} { + # the 503 was retried at the HTTP layer and the response of the + # second server is the one delivered to the client + txreq -url "/l7" + rxresp + expect resp.status == 200 + expect resp.http.x-second == "yes" + expect resp.http.x-retries == "1" + expect resp.http.x-redisp == "1" +} -run