Skip to content

Heartbeat can fail to protect an in-flight message, so the queue delivers it twice #294

Description

@blehnen

ConsumerHeartbeat intermittently reports more processed messages than were sent. Seen twice, on different data rows, on two different branches:

PR Row Expected Actual
#291 (7, 45, 280, 3, inMemoryDb: true, enableChaos: true) 7 8
#294 (commit conversion) (7, 45, 180, 3, inMemoryDb: false, enableChaos: false) 7 9

Why it is the test, not the change

  • Passes in isolation. 3/3 both times, including the row that had just failed. It only fails inside the full 200+ test run.
  • The second occurrence is on the non-chaos row, so injected faults are not required to trigger it.
  • It exercises the synchronous consumerConsumerCancelWorkShared uses creator.CreateConsumer(...). The branch it failed on converts only the asynchronous consumer's commit; ProcessMessage.cs and MessageProcessing.cs are untouched in that diff.

The race

ConsumerCancelWorkShared.RunConsumerInternal asserts messageCount == processedCount. The scenario is deliberately a race: a "bad" consumer takes messages, is disposed mid-flight, the heartbeat monitor resets its in-flight messages, and a good consumer picks them up. If the monitor resets a message the good consumer is already working — or the bad consumer completed one before disposal — the message is processed twice and the count overshoots.

Under full-suite load the workers are slower, which widens the window. The overshoot size tracks that: 8 the first time, 9 the second.

What to consider

The assertion may simply be wrong for what the scenario can guarantee. The test is about the heartbeat resetting stalled work, and reprocessing is the mechanism it relies on — so an exact-equality count is a stronger claim than the design supports. IsGreaterThanOrEqualTo(messageCount, ...) plus a separate assertion that every message reached a terminal state may be what was meant.

Worth deciding deliberately rather than re-running until green, which is what happened on #291.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions