From c5b736b7791009be8bf9c37d659eccca14574087 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 26 Dec 2025 09:03:38 +0000 Subject: [PATCH 1/2] Add failing test for SyncTransport ignoring BusNameStamp (Closes #16) When dispatching a message to eventBus (allowNoHandlers: true) via sync transport, SyncTransport incorrectly uses messageBus middleware instead of respecting the BusNameStamp. This causes NoHandlerForMessageException even though eventBus allows no handlers. --- ...ync-transport-respects-bus-name-stamp.neon | 52 +++++++++++++++++++ tests/Mocks/Message/EventMessage.php | 18 +++++++ 2 files changed, 70 insertions(+) create mode 100644 tests/Cases/E2E/Scenarios/__files__/sync-transport-respects-bus-name-stamp.neon create mode 100644 tests/Mocks/Message/EventMessage.php diff --git a/tests/Cases/E2E/Scenarios/__files__/sync-transport-respects-bus-name-stamp.neon b/tests/Cases/E2E/Scenarios/__files__/sync-transport-respects-bus-name-stamp.neon new file mode 100644 index 0000000..4f2959c --- /dev/null +++ b/tests/Cases/E2E/Scenarios/__files__/sync-transport-respects-bus-name-stamp.neon @@ -0,0 +1,52 @@ +# Test for issue #16: SyncTransport should respect BusNameStamp +# https://github.com/contributte/messenger/issues/16 +# +# When dispatching a message to eventBus (allowNoHandlers: true) via sync transport, +# the SyncTransport should use eventBus middleware, not the default messageBus middleware. +# +# This test currently FAILS because SyncTransport ignores BusNameStamp and uses +# the default bus middleware (messageBus with allowNoHandlers: false). + +input: + config: + extensions: + messenger: Contributte\Messenger\DI\MessengerExtension() + + messenger: + bus: + messageBus: + allowNoHandlers: false + eventBus: + allowNoHandlers: true + + transport: + sync: + dsn: sync:// + + routing: + Tests\Mocks\Message\EventMessage: [sync] + + dispatch: + bus: eventBus + message: Tests\Mocks\Message\EventMessage("test-event") + +output: + # Expected: Message should be sent and received without error + # because eventBus has allowNoHandlers: true + logger: + - level: info + message: 'Sending message {class} with {alias} sender using {sender}' + context: + class: Tests\Mocks\Message\EventMessage + alias: sync + sender: 'Symfony\Component\Messenger\Transport\Sync\SyncTransport' + + - level: info + message: 'Received message {class}' + context: + class: Tests\Mocks\Message\EventMessage + + - level: info + message: 'No handler for message {class}' + context: + class: Tests\Mocks\Message\EventMessage diff --git a/tests/Mocks/Message/EventMessage.php b/tests/Mocks/Message/EventMessage.php new file mode 100644 index 0000000..21a82c1 --- /dev/null +++ b/tests/Mocks/Message/EventMessage.php @@ -0,0 +1,18 @@ +text = $text; + } + +} From 6a850dffc6b0efed5f2e582f36ea7ce82ecd4ceb Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 26 Dec 2025 09:27:35 +0000 Subject: [PATCH 2/2] Fix SyncTransport ignoring BusNameStamp (Closes #16) Make RoutableMessageBus the default autowired MessageBusInterface instead of the first registered bus. This ensures that when SyncTransport dispatches messages, it respects the BusNameStamp and routes to the correct bus with its specific middleware configuration. Changes: - Individual buses are no longer autowired for MessageBusInterface - RoutableMessageBus is now the autowired MessageBusInterface - Added fallback bus (first registered bus) for messages without BusNameStamp --- src/DI/Pass/BusPass.php | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/DI/Pass/BusPass.php b/src/DI/Pass/BusPass.php index f848096..0ccf72d 100644 --- a/src/DI/Pass/BusPass.php +++ b/src/DI/Pass/BusPass.php @@ -36,10 +36,17 @@ public function loadPassConfiguration(): void $builder = $this->getContainerBuilder(); $config = $this->getConfig(); + $defaultBusName = null; + // Iterate all buses foreach ($config->bus as $name => $busConfig) { $middlewares = []; + // Track the first bus as the default/fallback bus + if ($defaultBusName === null) { + $defaultBusName = $name; + } + $builder->addDefinition($this->prefix(sprintf('bus.%s.locator', $name))) ->setFactory(ContainerServiceHandlersLocator::class, [[]]) ->setAutowired(false); @@ -77,13 +84,14 @@ public function loadPassConfiguration(): void ->addSetup('setLogger', [$this->prefix('@logger.logger')]); } - // Register message bus + // Register message bus - individual buses are NOT autowired for MessageBusInterface + // The RoutableMessageBus will be the autowired MessageBusInterface $builder->addDefinition($this->prefix(sprintf('bus.%s.bus', $name))) ->setFactory($busConfig->class ?? SymfonyMessageBus::class, [$middlewares]) - ->setAutowired($busConfig->autowired ?? count($builder->findByTag(MessengerExtension::BUS_TAG)) === 0) + ->setAutowired(false) ->setTags([MessengerExtension::BUS_TAG => $name]); - // Register bus wrapper + // Register bus wrapper (these can still be autowired for their specific types) if (isset($busConfig->wrapper) || isset(self::BUS_WRAPPERS[$name])) { $builder->addDefinition($this->prefix(sprintf('bus.%s.wrapper', $name))) ->setFactory($busConfig->wrapper ?? self::BUS_WRAPPERS[$name], [$this->prefix(sprintf('@bus.%s.bus', $name))]); @@ -95,10 +103,15 @@ public function loadPassConfiguration(): void ->setFactory(NetteContainer::class) ->setAutowired(false); - // Register routable bus (for CLI) + // Register routable bus as the default autowired MessageBusInterface + // This ensures SyncTransport respects BusNameStamp when routing messages (Closes #16) + // The fallback bus is used when no BusNameStamp is present $builder->addDefinition($this->prefix('bus.routable')) - ->setFactory(RoutableMessageBus::class, [$this->prefix('@bus.container')]) // @TODO fallbackBus - ->setAutowired(false); + ->setFactory(RoutableMessageBus::class, [ + $this->prefix('@bus.container'), + $defaultBusName !== null ? $this->prefix(sprintf('@bus.%s.bus', $defaultBusName)) : null, + ]) + ->setAutowired(true); // Register bus registry $builder->addDefinition($this->prefix('busRegistry'))