Skip to content

pass the delivery to ContainerAdapter.get, so request scopes aren't shared across retries - #360

Open
adenhertog wants to merge 1 commit into
masterfrom
issue-353-container-delivery-scope
Open

adenhertog wants to merge 1 commit into
masterfrom
issue-353-container-delivery-scope

Conversation

@adenhertog

Copy link
Copy Markdown
Contributor

Closes #353

Summary

ContainerAdapter.get is now also given the delivery being handled (context.transportMessage), and nestContainer() 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 Nest ContextId per message, keyed in a WeakMap by the message object, because that's the only per-message key get(type, { message, messageAttributes }) had.

Problem

InMemoryQueue hands 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 (and REQUEST) 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). invokeHandler passes the TransportMessage it's handling; the workflow registry passes messageHandlingContext.getReceived() (not its workflow copy), so the handlers and workflows of one delivery get the same object. Transports already return a new TransportMessage per read (the in-memory queue copies it, the others deserialize), and the bus already tracks deliveries by it (messagesBeingHandled); that's now written into the readNextMessage()/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). The REQUEST is still { message, attributes }.

  • Tests: bus-core checks a class handler and a class workflow get the same transportMessage per 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; the nestContainer spec covers the keying.

  • Docs: a "A scope per message" section on the dependency-injection page with a snippet, the NestJS request-scope paragraph, BusRequest/nestContainer JSDoc, and both CLAUDE.md files. 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 needed

  • Docs: updated docs/ for user-facing changes, or none needed

🤖 Generated with Claude Code

…hared across retries

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

Pass a per-delivery key to ContainerAdapter.get, so request scopes aren't shared across retries

1 participant