Skip to content

fix: defer re-entrant publishes of the same event - #9840

Draft
GuillaumeRx wants to merge 1 commit into
mainfrom
gr/messenger-defer-reentrant-publish
Draft

fix: defer re-entrant publishes of the same event#9840
GuillaumeRx wants to merge 1 commit into
mainfrom
gr/messenger-defer-reentrant-publish

Conversation

@GuillaumeRx

Copy link
Copy Markdown
Contributor

Explanation

Messenger delivered a re-entrant publish of the same event inline. When a subscriber published the event it was currently handling — directly, or indirectly through a delegated messenger (for example a stateChange subscriber that calls an action which triggers update() on the same controller) — the nested publish ran to completion, and then the in-progress publish resumed its subscriber loop and re-delivered its now-stale payload to the subscribers it had not yet reached. A downstream subscriber such as a UI store bridging controller state could therefore end up observing an older payload after a newer one.

This surfaced in the extension as a network filter that stayed on a just-added network even though the enabled-network map had already been restored: the restore's stateChange re-entered publish, and the stale "switched" payload was the last thing the UI received.

This change makes #publish defer a publish of an event that is already being published on the same messenger, then drain the deferred publishes in order once the in-progress publish finishes. Because the event stays marked as "publishing" while draining, further re-entrant publishes of that event are deferred and drained too. Re-entrant publishes of a different event still run inline. The fix covers delegated messengers as well, since delegated publishes funnel through the same #publish.

Note this is a small behavioral change: a re-entrant publish of the same event is now delivered after the current publish completes (still synchronously, within the same tick) rather than nested inside it.

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

@GuillaumeRx GuillaumeRx self-assigned this Aug 12, 2026
@GuillaumeRx
GuillaumeRx force-pushed the gr/messenger-defer-reentrant-publish branch 3 times, most recently from e18db6f to b2a6b5e Compare August 12, 2026 12:20
`Messenger` delivered a re-entrant publish of the same event inline, so
when a subscriber published the event it was handling (directly, or
indirectly through a delegated messenger), the in-progress publish would
resume afterwards and re-deliver its now-stale payload to the subscribers
it had not yet reached. A subscriber such as a UI store bridging controller
state could therefore end up observing an older payload after a newer one.

Defer a publish of an event that is already being published on the same
messenger, then drain the deferred publishes in order once the in-progress
publish finishes. Re-entrant publishes of a different event still run
inline.
@GuillaumeRx
GuillaumeRx force-pushed the gr/messenger-defer-reentrant-publish branch from b2a6b5e to 2ab366a Compare August 12, 2026 12:30
Comment thread packages/messenger/src/Messenger.ts

@Gudahtt Gudahtt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM!

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