From 7f774b4e9d7c731f18dacb1c23aa4492874b0eef Mon Sep 17 00:00:00 2001 From: Florian Guimier Date: Sat, 5 Dec 2020 15:11:05 +0100 Subject: [PATCH 1/2] Add group and class-filter options to FailedMessagesShowCommand --- src/Symfony/Component/Messenger/CHANGELOG.md | 1 + .../Command/FailedMessagesShowCommand.php | 58 ++++++++++++++++-- .../Command/FailedMessagesShowCommandTest.php | 60 ++++++++++++++++++- 3 files changed, 111 insertions(+), 8 deletions(-) mode change 100644 => 100755 src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 6bc1111fc85db..1e02703a74b17 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -27,6 +27,7 @@ CHANGELOG * Deprecate not setting the `reset_on_message` config option, its default value will change to `true` in 6.0 * Add log when worker should stop. * Add log when `SIGTERM` is received. + * Add the options `stats` and `class-filter` to `FailedMessagesShowCommand` 5.3 --- diff --git a/src/Symfony/Component/Messenger/Command/FailedMessagesShowCommand.php b/src/Symfony/Component/Messenger/Command/FailedMessagesShowCommand.php index 86f453bd0d553..b100d46da2211 100644 --- a/src/Symfony/Component/Messenger/Command/FailedMessagesShowCommand.php +++ b/src/Symfony/Component/Messenger/Command/FailedMessagesShowCommand.php @@ -39,6 +39,8 @@ protected function configure(): void new InputArgument('id', InputArgument::OPTIONAL, 'Specific message id to show'), new InputOption('max', null, InputOption::VALUE_REQUIRED, 'Maximum number of messages to list', 50), new InputOption('transport', null, InputOption::VALUE_OPTIONAL, 'Use a specific failure transport', self::DEFAULT_TRANSPORT_OPTION), + new InputOption('stats', null, InputOption::VALUE_NONE, 'Display the message count by class'), + new InputOption('class-filter', null, InputOption::VALUE_REQUIRED, 'Filter by a specific class name'), ]) ->setHelp(<<<'EOF' The %command.name% shows message that are pending in the failure transport. @@ -77,8 +79,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int throw new RuntimeException(sprintf('The "%s" receiver does not support listing or showing specific messages.', $failureTransportName)); } - if (null === $id = $input->getArgument('id')) { - $this->listMessages($failureTransportName, $io, $input->getOption('max')); + if ($input->getOption('stats')) { + $this->listMessagesPerClass($failureTransportName, $io, $input->getOption('max')); + } elseif (null === $id = $input->getArgument('id')) { + $this->listMessages($failureTransportName, $io, $input->getOption('max'), $input->getOption('class-filter')); } else { $this->showMessage($failureTransportName, $id, $io); } @@ -86,14 +90,25 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 0; } - private function listMessages(?string $failedTransportName, SymfonyStyle $io, int $max) + private function listMessages(?string $failedTransportName, SymfonyStyle $io, int $max, ?string $classFilter) { /** @var ListableReceiverInterface $receiver */ $receiver = $this->getReceiver($failedTransportName); $envelopes = $receiver->all($max); $rows = []; + + if ($classFilter) { + $io->comment(sprintf('Displaying only \'%s\' messages', $classFilter)); + } + foreach ($envelopes as $envelope) { + $currentClassName = \get_class($envelope->getMessage()); + + if ($classFilter && $classFilter !== $currentClassName) { + continue; + } + /** @var RedeliveryStamp|null $lastRedeliveryStamp */ $lastRedeliveryStamp = $envelope->last(RedeliveryStamp::class); /** @var ErrorDetailsStamp|null $lastErrorDetailsStamp */ @@ -106,13 +121,15 @@ private function listMessages(?string $failedTransportName, SymfonyStyle $io, in $rows[] = [ $this->getMessageId($envelope), - \get_class($envelope->getMessage()), + $currentClassName, null === $lastRedeliveryStamp ? '' : $lastRedeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s'), $errorMessage, ]; } - if (0 === \count($rows)) { + $rowsCount = \count($rows); + + if (0 === $rowsCount) { $io->success('No failed messages were found.'); return; @@ -120,13 +137,42 @@ private function listMessages(?string $failedTransportName, SymfonyStyle $io, in $io->table(['Id', 'Class', 'Failed at', 'Error'], $rows); - if (\count($rows) === $max) { + if ($rowsCount === $max) { $io->comment(sprintf('Showing first %d messages.', $max)); + } elseif ($classFilter) { + $io->comment(sprintf('Showing %d message(s).', $rowsCount)); } $io->comment(sprintf('Run messenger:failed:show {id} --transport=%s -vv to see message details.', $failedTransportName)); } + private function listMessagesPerClass(?string $failedTransportName, SymfonyStyle $io, int $max) + { + /** @var ListableReceiverInterface $receiver */ + $receiver = $this->getReceiver($failedTransportName); + $envelopes = $receiver->all($max); + + $countPerClass = []; + + foreach ($envelopes as $envelope) { + $c = \get_class($envelope->getMessage()); + + if (!isset($countPerClass[$c])) { + $countPerClass[$c] = [$c, 0]; + } + + ++$countPerClass[$c][1]; + } + + if (0 === \count($countPerClass)) { + $io->success('No failed messages were found.'); + + return; + } + + $io->table(['Class', 'Count'], $countPerClass); + } + private function showMessage(?string $failedTransportName, string $id, SymfonyStyle $io) { /** @var ListableReceiverInterface $receiver */ diff --git a/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php b/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php old mode 100644 new mode 100755 index 147176ee04d99..127b8e2636b98 --- a/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php +++ b/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php @@ -78,7 +78,7 @@ public function testBasicRunWithServiceLocator() Error Things are bad! Error Code 123 Error Class Exception - Transport async + Transport async EOF , $redeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s')), @@ -120,7 +120,7 @@ public function testMultipleRedeliveryFailsWithServiceLocator() Error Things are bad! Error Code 123 Error Class Exception - Transport async + Transport async EOF , $redeliveryStamp2->getRedeliveredAt()->format('Y-m-d H:i:s')), @@ -238,6 +238,62 @@ public function testListMessagesReturnsPaginatedMessagesWithServiceLocator() $this->assertStringContainsString('Showing first 1 messages.', $tester->getDisplay(true)); } + public function testListMessagesReturnsFilteredByClassMessage() + { + $sentToFailureStamp = new SentToFailureTransportStamp('async'); + $envelope = new Envelope(new \stdClass(), [ + new TransportMessageIdStamp(15), + $sentToFailureStamp, + new RedeliveryStamp(0), + ErrorDetailsStamp::create(new \RuntimeException('Things are bad!')), + ]); + $receiver = $this->createMock(ListableReceiverInterface::class); + $receiver->method('all')->with()->willReturn([$envelope]); + + $failureTransportName = 'failure_receiver'; + $serviceLocator = $this->createMock(ServiceLocator::class); + $serviceLocator->method('has')->with($failureTransportName)->willReturn(true); + $serviceLocator->method('get')->with($failureTransportName)->willReturn($receiver); + + $command = new FailedMessagesShowCommand('failure_receiver', $serviceLocator); + + $tester = new CommandTester($command); + $tester->execute([]); + $this->assertStringContainsString('Things are bad!', $tester->getDisplay(true)); + $tester->execute(['--class-filter' => 'stdClass']); + $this->assertStringContainsString('Things are bad!', $tester->getDisplay(true)); + $this->assertStringContainsString('Showing 1 message(s).', $tester->getDisplay(true)); + $this->assertStringContainsString('Displaying only \'stdClass\' messages', $tester->getDisplay(true)); + + $tester->execute(['--class-filter' => 'namespace\otherClass']); + $this->assertStringContainsString('[OK] No failed messages were found.', $tester->getDisplay(true)); + $this->assertStringContainsString('Displaying only \'namespace\otherClass\' messages', $tester->getDisplay(true)); + } + + public function testListMessagesReturnsCountByClassName() + { + $sentToFailureStamp = new SentToFailureTransportStamp('async'); + $envelope = new Envelope(new \stdClass(), [ + new TransportMessageIdStamp(15), + $sentToFailureStamp, + new RedeliveryStamp(0), + ErrorDetailsStamp::create(new \RuntimeException('Things are bad!')), + ]); + $receiver = $this->createMock(ListableReceiverInterface::class); + $receiver->method('all')->with()->willReturn([$envelope, $envelope]); + + $failureTransportName = 'failure_receiver'; + $serviceLocator = $this->createMock(ServiceLocator::class); + $serviceLocator->method('has')->with($failureTransportName)->willReturn(true); + $serviceLocator->method('get')->with($failureTransportName)->willReturn($receiver); + + $command = new FailedMessagesShowCommand('failure_receiver', $serviceLocator); + + $tester = new CommandTester($command); + $tester->execute(['--stats' => 1]); + $this->assertStringContainsString('stdClass 2', $tester->getDisplay(true)); + } + public function testInvalidMessagesThrowsExceptionWithServiceLocator() { $receiver = $this->createMock(ListableReceiverInterface::class); From e99d2ca9bacc158da94b52b66fbdcbb55b351220 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 21 Jul 2022 11:22:57 +0200 Subject: [PATCH 2/2] Finish work --- src/Symfony/Component/Messenger/CHANGELOG.md | 2 +- .../Component/Messenger/Command/FailedMessagesShowCommand.php | 2 +- .../Messenger/Tests/Command/FailedMessagesShowCommandTest.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) mode change 100755 => 100644 src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 1e02703a74b17..000bb702fe297 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -27,7 +27,7 @@ CHANGELOG * Deprecate not setting the `reset_on_message` config option, its default value will change to `true` in 6.0 * Add log when worker should stop. * Add log when `SIGTERM` is received. - * Add the options `stats` and `class-filter` to `FailedMessagesShowCommand` + * Add `--stats` and `--class-filter` options to `FailedMessagesShowCommand` 5.3 --- diff --git a/src/Symfony/Component/Messenger/Command/FailedMessagesShowCommand.php b/src/Symfony/Component/Messenger/Command/FailedMessagesShowCommand.php index b100d46da2211..8abef72aecf1b 100644 --- a/src/Symfony/Component/Messenger/Command/FailedMessagesShowCommand.php +++ b/src/Symfony/Component/Messenger/Command/FailedMessagesShowCommand.php @@ -90,7 +90,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 0; } - private function listMessages(?string $failedTransportName, SymfonyStyle $io, int $max, ?string $classFilter) + private function listMessages(?string $failedTransportName, SymfonyStyle $io, int $max, string $classFilter = null) { /** @var ListableReceiverInterface $receiver */ $receiver = $this->getReceiver($failedTransportName); diff --git a/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php b/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php old mode 100755 new mode 100644 index 127b8e2636b98..7476970ac30f4 --- a/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php +++ b/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php @@ -78,7 +78,7 @@ public function testBasicRunWithServiceLocator() Error Things are bad! Error Code 123 Error Class Exception - Transport async + Transport async EOF , $redeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s')), @@ -120,7 +120,7 @@ public function testMultipleRedeliveryFailsWithServiceLocator() Error Things are bad! Error Code 123 Error Class Exception - Transport async + Transport async EOF , $redeliveryStamp2->getRedeliveredAt()->format('Y-m-d H:i:s')),