Repository navigation
pass the delivery to ContainerAdapter.get, so request scopes aren't shared across retries - #360
Open
adenhertog wants to merge 1 commit into
Open
adenhertog wants to merge 1 commit into
adenhertog wants to merge 1 commit into
Conversation
…hared across retries Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #353
Summary
ContainerAdapter.getis now also given the delivery being handled (context.transportMessage), andnestContainer()keys its request scopes on it, so a retry or a re-send of the same message object gets a fresh scope.Background
nestContainer()in@node-ts/bus-nestjs(#352) gives request-scoped providers a NestContextIdper message, keyed in aWeakMapby the message object, because that's the only per-message keyget(type, { message, messageAttributes })had.Problem
InMemoryQueuehands out the same message object on every read of a returned message, and queues the sent object itself, so a retry, or a second send of the same object, reused the request-scoped providers (andREQUEST) of the earlier delivery. State built up by a failed attempt leaked into the retry. The new bus-nestjs test fails on master for both the retry and the re-send.Approach
bus-core: a new exported
ContainerContext(message,messageAttributes,transportMessage, all optional, so custom adapters are unaffected).invokeHandlerpasses theTransportMessageit's handling; the workflow registry passesmessageHandlingContext.getReceived()(not its workflow copy), so the handlers and workflows of one delivery get the same object. Transports already return a newTransportMessageper read (the in-memory queue copies it, the others deserialize), and the bus already tracks deliveries by it (messagesBeingHandled); that's now written into thereadNextMessage()/Receiver.receive()contract and the custom transport page.bus-nestjs: scopes are keyed on
context.transportMessage. Without one, each call gets a fresh scope (never sharing is safer than keying on the message). TheREQUESTis still{ message, attributes }.Tests: bus-core checks a class handler and a class workflow get the same
transportMessageper delivery, and the retry and second send new ones while the message object stays the same. bus-nestjs checks a retried and a re-sent command get new request-scoped providers without the earlier state, still shared by the handler and workflow of each delivery; thenestContainerspec covers the keying.Docs: a "A scope per message" section on the dependency-injection page with a snippet, the NestJS request-scope paragraph,
BusRequest/nestContainerJSDoc, and bothCLAUDE.mdfiles. Changeset: bus-core minor, not breaking; the unreleased bus-nestjs changeset is reworded.This is original work under the clean-room policy, not ported, translated or copied from another messaging framework
Added a changeset (
pnpm changeset) for user-facing changes to published packages, or none is neededDocs: updated
docs/for user-facing changes, or none needed🤖 Generated with Claude Code