diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md
index c4eae318d3518..068de7984a00a 100644
--- a/src/Symfony/Component/Messenger/CHANGELOG.md
+++ b/src/Symfony/Component/Messenger/CHANGELOG.md
@@ -4,6 +4,7 @@ CHANGELOG
7.3
---
+ * Add `--exclude-receivers` option to the `messenger:consume command`
* Add `CloseableTransportInterface` to allow closing the transport
* Add `SentForRetryStamp` that identifies whether a failed message was sent for retry
* Add `Symfony\Component\Messenger\Middleware\DeduplicateMiddleware` and `Symfony\Component\Messenger\Stamp\DeduplicateStamp`
diff --git a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php
index 9fcb6a5e17e80..262aba27ecf66 100644
--- a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php
+++ b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php
@@ -77,6 +77,7 @@ protected function configure(): void
new InputOption('queues', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Limit receivers to only consume from the specified queues'),
new InputOption('no-reset', null, InputOption::VALUE_NONE, 'Do not reset container services after each message'),
new InputOption('all', null, InputOption::VALUE_NONE, 'Consume messages from all receivers'),
+ new InputOption('exclude-receivers', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Exclude specific receivers/transports from consumption (can only be used with --all)'),
new InputOption('keepalive', null, InputOption::VALUE_OPTIONAL, 'Whether to use the transport\'s keepalive mechanism if implemented', self::DEFAULT_KEEPALIVE_INTERVAL),
])
->setHelp(<<<'EOF'
@@ -122,6 +123,10 @@ protected function configure(): void
Use the --all option to consume from all receivers:
php %command.full_name% --all
+
+Use the --exclude-receivers option to exclude specific receivers/transports from consumption (can only be used with --all):
+
+ php %command.full_name% --all --exclude-receivers=
EOF
)
;
@@ -132,6 +137,10 @@ protected function initialize(InputInterface $input, OutputInterface $output): v
if ($input->hasParameterOption('--keepalive')) {
$this->getApplication()->setAlarmInterval((int) ($input->getOption('keepalive') ?? self::DEFAULT_KEEPALIVE_INTERVAL));
}
+
+ if ($input->getOption('exclude-receivers') && !$input->getOption('all')) {
+ throw new InvalidOptionException('The --exclude-receivers option can only be used with the --all option.');
+ }
}
protected function interact(InputInterface $input, OutputInterface $output): void
@@ -169,9 +178,22 @@ protected function interact(InputInterface $input, OutputInterface $output): voi
protected function execute(InputInterface $input, OutputInterface $output): int
{
+ if ($input->getOption('exclude-receivers') && !$input->getOption('all')) {
+ throw new InvalidOptionException('The --exclude-receivers option can only be used with the --all option.');
+ }
+
$receivers = [];
$rateLimiters = [];
$receiverNames = $input->getOption('all') ? $this->receiverNames : $input->getArgument('receivers');
+
+ if ($input->getOption('all') && $excludedTransports = $input->getOption('exclude-receivers')) {
+ $receiverNames = array_diff($receiverNames, $excludedTransports);
+
+ if (!$receiverNames) {
+ throw new RuntimeException('All transports/receivers have been excluded. Please specify at least one to consume from.');
+ }
+ }
+
foreach ($receiverNames as $receiverName) {
if (!$this->receiverLocator->has($receiverName)) {
$message = \sprintf('The receiver "%s" does not exist.', $receiverName);
@@ -276,6 +298,10 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti
if ($input->mustSuggestOptionValuesFor('bus')) {
$suggestions->suggestValues($this->busIds);
}
+
+ if ($input->mustSuggestOptionValuesFor('exclude-receivers')) {
+ $suggestions->suggestValues($this->receiverNames);
+ }
}
public function getSubscribedSignals(): array
diff --git a/src/Symfony/Component/Messenger/Tests/Command/ConsumeMessagesCommandTest.php b/src/Symfony/Component/Messenger/Tests/Command/ConsumeMessagesCommandTest.php
index 8552a64f1a291..3ddc36c952069 100644
--- a/src/Symfony/Component/Messenger/Tests/Command/ConsumeMessagesCommandTest.php
+++ b/src/Symfony/Component/Messenger/Tests/Command/ConsumeMessagesCommandTest.php
@@ -242,7 +242,7 @@ public function testRunWithMemoryLimit()
$busLocator = new Container();
$busLocator->set('dummy-bus', $bus);
- $logger = new class() implements LoggerInterface {
+ $logger = new class implements LoggerInterface {
use LoggerTrait;
public array $logs = [];
@@ -334,4 +334,156 @@ public static function provideCompletionSuggestions()
yield 'receiver (no repeat)' => [['async', ''], ['async_high', 'failed']];
yield 'option --bus' => [['--bus', ''], ['messenger.bus.default']];
}
+
+ public function testRunWithExcludeReceiversOption()
+ {
+ $envelope1 = new Envelope(new \stdClass(), [new BusNameStamp('dummy-bus')]);
+ $envelope2 = new Envelope(new \stdClass(), [new BusNameStamp('dummy-bus')]);
+ $envelope3 = new Envelope(new \stdClass(), [new BusNameStamp('dummy-bus')]);
+
+ $receiver1 = $this->createMock(ReceiverInterface::class);
+ $receiver1->method('get')->willReturn([$envelope1]);
+ $receiver2 = $this->createMock(ReceiverInterface::class);
+ $receiver2->method('get')->willReturn([$envelope2]);
+ $receiver3 = $this->createMock(ReceiverInterface::class);
+ $receiver3->method('get')->willReturn([$envelope3]);
+
+ $receiverLocator = new Container();
+ $receiverLocator->set('dummy-receiver1', $receiver1);
+ $receiverLocator->set('dummy-receiver2', $receiver2);
+ $receiverLocator->set('dummy-receiver3', $receiver3);
+
+ $bus = $this->createMock(MessageBusInterface::class);
+ // Only 2 messages should be dispatched (receiver1 and receiver3, receiver2 is excluded)
+ $bus->expects($this->exactly(2))->method('dispatch');
+
+ $busLocator = new Container();
+ $busLocator->set('dummy-bus', $bus);
+
+ $command = new ConsumeMessagesCommand(
+ new RoutableMessageBus($busLocator),
+ $receiverLocator, new EventDispatcher(),
+ receiverNames: ['dummy-receiver1', 'dummy-receiver2', 'dummy-receiver3']
+ );
+
+ $application = new Application();
+ if (method_exists($application, 'addCommand')) {
+ $application->addCommand($command);
+ } else {
+ $application->add($command);
+ }
+ $tester = new CommandTester($application->get('messenger:consume'));
+ $tester->execute([
+ '--all' => true,
+ '--exclude-receivers' => ['dummy-receiver2'],
+ '--limit' => 2,
+ ]);
+
+ $tester->assertCommandIsSuccessful();
+ $this->assertStringContainsString('[OK] Consuming messages from transports "dummy-receiver1, dummy-receiver3"', $tester->getDisplay());
+ }
+
+ public function testRunWithExcludeReceiversMultipleQueues()
+ {
+ $envelope1 = new Envelope(new \stdClass(), [new BusNameStamp('dummy-bus')]);
+ $envelope2 = new Envelope(new \stdClass(), [new BusNameStamp('dummy-bus')]);
+ $envelope3 = new Envelope(new \stdClass(), [new BusNameStamp('dummy-bus')]);
+ $envelope4 = new Envelope(new \stdClass(), [new BusNameStamp('dummy-bus')]);
+
+ $receiver1 = $this->createMock(ReceiverInterface::class);
+ $receiver1->method('get')->willReturn([$envelope1]);
+ $receiver2 = $this->createMock(ReceiverInterface::class);
+ $receiver2->method('get')->willReturn([$envelope2]);
+ $receiver3 = $this->createMock(ReceiverInterface::class);
+ $receiver3->method('get')->willReturn([$envelope3]);
+ $receiver4 = $this->createMock(ReceiverInterface::class);
+ $receiver4->method('get')->willReturn([$envelope4]);
+
+ $receiverLocator = new Container();
+ $receiverLocator->set('dummy-receiver1', $receiver1);
+ $receiverLocator->set('dummy-receiver2', $receiver2);
+ $receiverLocator->set('dummy-receiver3', $receiver3);
+ $receiverLocator->set('dummy-receiver4', $receiver4);
+
+ $bus = $this->createMock(MessageBusInterface::class);
+ // Only 2 messages should be dispatched (receiver1 and receiver4, receiver2 and receiver3 are excluded)
+ $bus->expects($this->exactly(2))->method('dispatch');
+
+ $busLocator = new Container();
+ $busLocator->set('dummy-bus', $bus);
+
+ $command = new ConsumeMessagesCommand(
+ new RoutableMessageBus($busLocator),
+ $receiverLocator, new EventDispatcher(),
+ receiverNames: ['dummy-receiver1', 'dummy-receiver2', 'dummy-receiver3', 'dummy-receiver4']
+ );
+
+ $application = new Application();
+ if (method_exists($application, 'addCommand')) {
+ $application->addCommand($command);
+ } else {
+ $application->add($command);
+ }
+ $tester = new CommandTester($application->get('messenger:consume'));
+ $tester->execute([
+ '--all' => true,
+ '--exclude-receivers' => ['dummy-receiver2', 'dummy-receiver3'],
+ '--limit' => 2,
+ ]);
+
+ $tester->assertCommandIsSuccessful();
+ $this->assertStringContainsString('[OK] Consuming messages from transports "dummy-receiver1, dummy-receiver4"', $tester->getDisplay());
+ }
+
+ public function testExcludeReceiverssWithoutAllOptionThrowsException()
+ {
+ $receiverLocator = new Container();
+ $receiverLocator->set('dummy-receiver', new \stdClass());
+
+ $command = new ConsumeMessagesCommand(new RoutableMessageBus(new Container()), $receiverLocator, new EventDispatcher());
+
+ $application = new Application();
+ if (method_exists($application, 'addCommand')) {
+ $application->addCommand($command);
+ } else {
+ $application->add($command);
+ }
+ $tester = new CommandTester($application->get('messenger:consume'));
+
+ $this->expectException(InvalidOptionException::class);
+ $this->expectExceptionMessage('The --exclude-receivers option can only be used with the --all option.');
+ $tester->execute([
+ 'receivers' => ['dummy-receiver'],
+ '--exclude-receivers' => ['dummy-receiver'],
+ ]);
+ }
+
+ public function testExcludeReceiversWithAllQueuesExcludedThrowsException()
+ {
+ $receiverLocator = new Container();
+ $receiverLocator->set('dummy-receiver1', new \stdClass());
+ $receiverLocator->set('dummy-receiver2', new \stdClass());
+
+ $command = new ConsumeMessagesCommand(
+ new RoutableMessageBus(new Container()),
+ $receiverLocator,
+ new EventDispatcher(),
+ receiverNames: ['dummy-receiver1', 'dummy-receiver2']
+ );
+
+ $application = new Application();
+ if (method_exists($application, 'addCommand')) {
+ $application->addCommand($command);
+ } else {
+ $application->add($command);
+ }
+ $tester = new CommandTester($application->get('messenger:consume'));
+
+ $this->expectException(\Symfony\Component\Console\Exception\RuntimeException::class);
+ $this->expectExceptionMessage('All transports/receivers have been excluded. Please specify at least one to consume from.');
+ $tester->execute([
+ '--all' => true,
+ '--exclude-receivers' => ['dummy-receiver1', 'dummy-receiver2'],
+ ]);
+ }
}
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy