feat(v3): per-message send functions for multi-message operations (#140) - #332
Merged
Merged
Conversation
…ations (#140) Operations carrying more than one message only exposed the first one. Now, when an operation (or its channel) has several messages, one send function is generated per message (SendAs<Op>For<Message>), each sending its own message type. Single-message operations are unchanged (byte-identical output). Also makes Channel.GetMessage deterministic (it ranged a map, which could produce unstable / non-compiling generated code for channels with several messages). Reception of multiple message types on a channel is left for a follow-up (it requires reworking the address-keyed subscription map); the subscribe side still handles the first message. Addresses #140 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 12, 2026
lerenn
added a commit
that referenced
this pull request
Jun 14, 2026
) Follow-up to #140/#332, which shipped the send side. When a receive operation (or its channel) declares more than one message, generate one subscribe function per message instead of silently handling only the first one: - SubscribeToXForUserCreated / SubscribeToXForUserDeleted, with one callback per message type, plus matching UnsubscribeFromXFor... and per-message methods on the subscriber interface. Single-message operations are unchanged (byte-identical output). - A single broker subscription is opened per channel and multiplexed to the registered per-message handlers, so several per-message subscriptions on one channel no longer collide. - Received messages are discriminated with a try-each-until-valid strategy (unmarshal + validate against each candidate schema using go-playground/validator) and dispatched to the first match. - A message matching none of the expected types is nacked and surfaced through the error handler as the new extensions.ErrNoMatchingMessage. Adds a broker-backed regression test (test/v3/issues/333) covering dispatch of two distinct message types on one channel, the no-match path, and per-message unsubscribe. Documents the behavior and the validator dependency in the README. Co-authored-by: Louis FRADIN <louis.fradin@pm.me> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Issue
Addresses #140 — operations carrying more than one message only ever used the first one (
op.Messages[0] // TODO: change); the others were silently discarded.Decision
Per the maintainer's direction: per-message methods (additive), and the send side first (the receive side needs a separate design — see below).
Change
When an operation (or its channel) declares more than one message, one send function is generated per message, named
<SendFunc>For<Message>:Single-message operations are unchanged —
go generate ./...produces no diff outside the new test.Also fixes a latent bug:
Channel.GetMessageranged amap(non-deterministic), which for multi-message channels produced unstable and even non-compiling generated code (the callback type and thebrokerMessageTo…type could resolve to different messages). It now returns the lowest-named message deterministically.Scope / follow-up
The receive side is intentionally not included. The chosen per-message design (
SubscribeToXForA/SubscribeToXForB) collides with the controller's address-keyed subscription map (c.subscriptions[addr]+ an "already subscribed" guard), so supporting it needs a rework of subscription management plus the agreed try-each-until-valid discrimination. The subscribe side continues to handle the first message, so this PR is "Addresses" rather than "Fixes" #140.Test
test/v3/issues/140sends both messages through a capturing mock broker and asserts each per-message function publishes its own payload on the channel. It fails to compile before the change (the functions don't exist) and passes after.🤖 Generated with Claude Code