Skip to content

Fix rare HAProxy crash resulting from a watchdog failure - #42

Merged
jacquesh merged 5 commits into
bloomberg:mainfrom
jacquesh:fix-weir-watchdog-failure
Aug 5, 2026
Merged

Fix rare HAProxy crash resulting from a watchdog failure#42
jacquesh merged 5 commits into
bloomberg:mainfrom
jacquesh:fix-weir-watchdog-failure

Conversation

@jacquesh

Copy link
Copy Markdown
Contributor

Description

For a while we've been seeing strange crashes in HAProxy that we've been unable to pin down. Recent investigation by @aokhovat and @BBoozmen highlighted that the problem lies in the way we update the channel's analyse_exp (or don't, as the case may be). The fix is threefold (organised into separate commits with descriptive messages, this is just s summary):

  1. We need to add a callback for either http_end or channel_end_analyze to reset the analyser expiry. I opted for channel_end_analyze for consistency with flt_bwlim (on which flt_weir is modelled)
  2. We need to stop sharing next_allowed_send_tick between the request and the response, to avoid weird sharing behaviour in the case where the response starts streaming before the request transfer finishes.
  3. We need to ensure that we reset analyse_exp during payload filtering even if the buffer we get given for forwarding is 0 bytes long (which is also something that flt_bwlim is already doing but we were not).

I've also updated/added comments to reflect our new understanding.

Type of Change

  • Bugfix
  • New Feature
  • Breaking Change
  • Refactor
  • Documentation
  • Other (please describe)

Checklist

  • I have read the contributing guidelines
  • Existing issues have been referenced (where applicable)
  • I have verified this change is not present in other open pull requests
  • Functionality is documented
  • New code contribution is covered by automated tests

@jacquesh
jacquesh requested a review from a team as a code owner April 30, 2026 13:30
jacquesh added 5 commits June 9, 2026 10:09
As documented this provides some fallback protection against odd execution orderings that could otherwise
cause a crash. This also brings us slightly back in line with flt_bwlim (of which the weir filter is modeled)
which also does this.
I now better understand why this is required so it makes sense to reflect this here. Adding the assert also
serves to communicate how its meant to function, lines up with flt_bwlim and covers us against future weird
behaviour.
Here we're just swapping the order in which we check the various conditions before attempting to throttle
a stream. The check for a missing remote_addr is only required so that we can safely call the rl_* functions
so it got moved down there accordingly. The check for non-zero length was moved further down and in particular
was separated from the check against next_allowed_send_tick expiring.

This second one is most sigificant: We do sometimes get called with len=0 and by enabling a reset of the
next send tick (and by extension the update to analyse_exp) we guard against situations where we're done
processing the payload of this stream, but are still being called with zero length. In this situation we
definitely do not want to delay processing any further and we need to make sure that analyse_exp is set
accordingly.

Without this update if we got throttled and after that only got called with length 0 for any reason, we
would never reset analyse_exp to TICK_ETERNITY and would break our contract with HAProxy in doing so,
causing weird behaviour like stuck streams and potentially crashes.
Unlike flt_bwlim our filter is enabled once and applies to both the request and the response. This means
that the state on our filter is shared between the two. If we have a single counter to track the next
send tick across both the request and the response, then if the two are running concurrently, they can
incorrectly slow each other down.

For example if you're streaming up request data while streaming back the same amount of response data
and your upload limit is lower than your download limit, then the response data could be slowed down just
because your request data is being streamed up faster than your upload limit.
This has a significantly clearer justification for being the correct callback for the HTTP case than end_analyse.
@jacquesh
jacquesh force-pushed the fix-weir-watchdog-failure branch from 710d42d to 3a988cb Compare June 9, 2026 09:28
@jacquesh
jacquesh merged commit 3e8e0e7 into bloomberg:main Aug 5, 2026
2 checks passed
@jacquesh
jacquesh deleted the fix-weir-watchdog-failure branch August 5, 2026 09:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants