Skip to content

CircuitBreakingTests: durable_and_not_parallel.the_circuit_breaker_should_trip_and_restart is unreliable on CI #3680

Description

@jeremydmiller

CircuitBreakingTests.RabbitMq.durable_and_not_parallel.the_circuit_breaker_should_trip_and_restart fails intermittently on CICircuitBreaking, always with the same shape:

System.TimeoutException : Listener did not process the expected message count 1200
in the time allowed. Only 1190 unique messages received. 10 of 1200 published never made it.

Seen most recently on #3678 (a docs/tests-only PR that cannot touch this code path), where the parent commit had passed the same job 31/31. CICircuitBreaking has also been red on #3656.

Skipped for now via a [Fact(Skip = ...)] override on the durable_and_not_parallel subclass, so unrelated PRs are not blocked. The sibling variants (buffered, inline, local) and the other assertion in this class (everything_is_wonderful_..._do_not_ever_trip) still run, so circuit-breaker trip/restart behavior remains covered.

Why this needs a real fix, not a longer timeout

This is the same test that GH-3137 already touched twice — first with ProcessingBudget raised to 3 minutes, then with RequiredProcessedCountOnTrip made overridable so buffered variants could require fewer than 1200. The lesson recorded there was that a "flake" in this test turned out to be a genuine message-loss bug, so the small-N loss should be explained before it is tuned away.

The durable variant is exactly the one that should not lose messages: buffered mode acks to the broker as soon as a message lands in the in-memory buffer (documented tradeoff, hence its lower required count), but durable persists before acking. Losing 10 of 1200 under a durable inbox is either:

  1. a real gap in the requeue/circuit-pause interaction — messages requeued around the moment the breaker trips and the listener tears down, or
  2. a test-harness accounting problem — MessageRecorder.TrackPublished racing the trip, or the waiter resolving against a count that double-counts requeues.

Suggested work

  • Determine which of the two it is. Instrument the run to dump the 10 missing message ids and their last known state (published / received / requeued / in the inbox) rather than only the count.
  • If (1): fix the loss and un-skip. This would be a real durability bug worth its own issue.
  • If (2): make the harness deterministic — gate on listener lifecycle transitions rather than a wall-clock budget over a fixed count, in the same spirit as waitForListenerToResumeAsync — and un-skip.
  • Either way, remove the Skip and reference this issue in the commit.

Repro

docker compose up -d rabbitmq postgresql
dotnet test src/Transports/RabbitMQ/CircuitBreakingTests/CircuitBreakingTests.csproj \
  --filter "FullyQualifiedName~durable_and_not_parallel"

Loads the runner (it is a 1200-message churn test), so it reproduces most readily on a contended machine.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions