@@ -67,8 +67,10 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
6767// lb_retries <retries>
6868// lb_try_duration <duration>
6969// lb_try_interval <interval>
70- // lb_retry_on <conditions...>
71- // lb_retry_match <request-matcher>
70+ // lb_retry_match {
71+ // <request-matcher>
72+ // status <codes...>
73+ // }
7274//
7375// # active health checking
7476// health_uri <uri>
@@ -324,36 +326,20 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
324326 h .LoadBalancing .TryInterval = caddy .Duration (dur )
325327
326328 case "lb_retry_match" :
327- matcherSet , err := caddyhttp .ParseCaddyfileNestedMatcherSet (d )
328- if err != nil {
329- return d .Errf ("failed to parse lb_retry_match: %v" , err )
330- }
331329 if h .LoadBalancing == nil {
332330 h .LoadBalancing = new (LoadBalancing )
333331 }
334- h .LoadBalancing .RetryMatchRaw = append (h .LoadBalancing .RetryMatchRaw , matcherSet )
335-
336- case "lb_retry_on" :
337- args := d .RemainingArgs ()
338- if len (args ) == 0 {
339- return d .ArgErr ()
340- }
341- if h .LoadBalancing == nil {
342- h .LoadBalancing = new (LoadBalancing )
332+ condSet , matcherSet , err := parseRetryMatchBlock (d )
333+ if err != nil {
334+ return err
343335 }
344- for _ , arg := range args {
345- switch arg {
346- case "empty_response" , "tls_handshake_error" , "response_timeout" :
347- h .LoadBalancing .RetryOn = append (h .LoadBalancing .RetryOn , arg )
348- default :
349- if len (arg ) == 3 && strings .HasSuffix (arg , "xx" ) {
350- arg = arg [:1 ]
351- }
352- if _ , err := strconv .Atoi (arg ); err != nil {
353- return d .Errf ("bad retry_on condition '%s': must be a keyword or status code" , arg )
354- }
355- h .LoadBalancing .RetryOn = append (h .LoadBalancing .RetryOn , arg )
336+ if condSet != nil {
337+ if matcherSet != nil {
338+ condSet .MatchRaw = matcherSet
356339 }
340+ h .LoadBalancing .RetryConditionsRaw = append (h .LoadBalancing .RetryConditionsRaw , condSet )
341+ } else if matcherSet != nil {
342+ h .LoadBalancing .RetryMatchRaw = append (h .LoadBalancing .RetryMatchRaw , matcherSet )
357343 }
358344
359345 case "health_uri" :
@@ -1710,6 +1696,46 @@ func (u *MultiUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
17101696 return nil
17111697}
17121698
1699+ // parseRetryMatchBlock parses the lb_retry_match block, which may contain
1700+ // standard request matchers alongside "status" directives.
1701+ // It returns a RetryConditionSet (if status is present) and/or
1702+ // a matcher set (from request matchers). If only matchers are present, the
1703+ // condition set is nil (backward compatible with retry_match).
1704+ func parseRetryMatchBlock (d * caddyfile.Dispenser ) (* RetryConditionSet , caddy.ModuleMap , error ) {
1705+ var condSet RetryConditionSet
1706+ var hasConditions bool
1707+
1708+ matcherSet , err := caddyhttp .ParseCaddyfileNestedMatcherSetWithFilter (d , func (name string , d * caddyfile.Dispenser ) (bool , error ) {
1709+ if name != "status" {
1710+ return false , nil
1711+ }
1712+ args := d .RemainingArgs ()
1713+ if len (args ) == 0 {
1714+ return false , d .ArgErr ()
1715+ }
1716+ for _ , arg := range args {
1717+ if len (arg ) == 3 && strings .HasSuffix (arg , "xx" ) {
1718+ arg = arg [:1 ]
1719+ }
1720+ code , err := strconv .Atoi (arg )
1721+ if err != nil {
1722+ return false , d .Errf ("bad status value '%s': %v" , arg , err )
1723+ }
1724+ condSet .Status = append (condSet .Status , code )
1725+ }
1726+ hasConditions = true
1727+ return true , nil
1728+ })
1729+ if err != nil {
1730+ return nil , nil , err
1731+ }
1732+
1733+ if hasConditions {
1734+ return & condSet , matcherSet , nil
1735+ }
1736+ return nil , matcherSet , nil
1737+ }
1738+
17131739const matcherPrefix = "@"
17141740
17151741// Interface guards
0 commit comments