Skip to content

Forward reset and replay handling through the platform wrapper - #197

Merged
CodeDrivenMitch merged 2 commits into
mainfrom
fix/forward-reset-handling
Nov 3, 2026
Merged

CodeDrivenMitch merged 2 commits into
mainfrom
fix/forward-reset-handling

Conversation

@CodeDrivenMitch

@CodeDrivenMitch CodeDrivenMitch commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

The client wraps the event handling component of each pooled streaming and subscribing processor in AxoniqPlatformEventHandlingComponent. The wrapper forwards only event handling. For the other methods, the EventHandlingComponent defaults apply. This has three effects in 5.4.0:

  • Reset handlers do not run. A projection that clears its tables in a reset handler replays on top of its old data.
  • Replay status handlers do not run. They do not see a replay start or end.
  • A processor always accepts resetTokens(), also when no component supports a reset. During the replay, the processor also sends events to those components.

Change

The wrapper now forwards these methods to the wrapped component:

  • supportsReset
  • handle(ResetContext, ProcessingContext)
  • handle(ReplayStatusChanged, ProcessingContext)
  • supports
  • unwrap

This follows the framework's DelegatingEventHandlingComponent. The wrapper does not extend that class. Its protected delegate field clashes with the public delegate property that DeadLetterManager reads.

Tests

AxoniqPlatformEventHandlingComponentResetTest has five tests:

  • A reset calls the reset handler of the wrapped component.
  • The processor does not support a reset when the wrapped component does not.
  • A replay status change reaches the wrapped component.
  • A reset clears the dead-letter queue.
  • A reset keeps the dead letters when clearOnReset is false.

The third test calls the wrapper directly. The other tests start a pooled streaming processor with the wrapper. The last two tests also turn on the dead-letter queue.

All five tests fail on main and pass with this change. The full suite passes, except for the four AxoniqConsoleRSocketClientToxiproxyIntegrationTest tests. These tests also fail on main in my environment.

Note

The dead-letter component sits below this wrapper. clearOnReset is true by default. With this change, a reset clears the dead-letter queue. This also applies to a reset from the Platform UI. In 5.4.0, dead letters stayed after a reset. This is the correct framework behaviour, but users will notice it. The release notes must say so. To keep dead letters, set clearOnReset(false) on the DeadLetterQueueConfiguration.

#196 also adds the supports forwarding. The second PR to merge gets a small conflict.

AxoniqPlatformEventHandlingComponent wraps the event handling component
of every pooled streaming and subscribing processor. It forwarded only
event handling, so the EventHandlingComponent defaults applied for the
rest:

- supportsReset() always returned true, so a processor accepted
  resetTokens() and sent replayed events to components that do not
  support a reset.
- handle(ResetContext) returned an empty stream, so reset handlers
  never ran. A projection that clears its tables in a reset handler
  replayed on top of its old data.
- handle(ReplayStatusChanged) returned an empty stream, so replay
  status handlers never saw a replay start or end.

The wrapper now forwards supportsReset, both reset and replay status
handle methods, supports and unwrap to the wrapped component. This
follows the framework's DelegatingEventHandlingComponent. The wrapper
does not extend that class, because its protected delegate field
clashes with the public delegate property that DeadLetterManager reads.

@stefanmirkovic stefanmirkovic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The wrapper now forwards all five default methods, the same set DelegatingEventHandlingComponent overrides, and the three tests fail on main and pass here (ran them locally).

One thing worth a line in the release notes: the DLQ component sits below this wrapper and clearOnReset defaults to true, so with this fix a reset now clears the dead-letter queue. Until now dead letters survived resets for everyone using the client, including resets triggered from the Platform UI. It’s the correct framework behaviour, but users will notice. A test for that path would be nice too.

Nit: the third test calls the wrapper directly rather than going through a processor, so the PR description is slightly off there.

The dead-letter component sits below the platform wrapper. Now that the
wrapper forwards resets, a reset clears the dead-letter queue when
clearOnReset is true, which is the default. Cover both settings of
clearOnReset so this behaviour change stays deliberate.
@CodeDrivenMitch
CodeDrivenMitch merged commit 6c8cb8f into main Nov 3, 2026
2 checks passed
@CodeDrivenMitch CodeDrivenMitch mentioned this pull request Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants