8000 [Messenger] Add `--class-filter` option to the `messenger:failed:remo… · symfony/symfony@8557685 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8557685

Browse files
[Messenger] Add --class-filter option to the messenger:failed:remove command
1 parent 6c0058a commit 8557685

File tree

3 files changed

+87
-4
lines changed
  • Command
  • Tests/Command
  • 3 files changed

    +87
    -4
    lines changed

    src/Symfony/Component/Messenger/CHANGELOG.md

    Lines changed: 1 addition & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -7,6 +7,7 @@ CHANGELOG
    77
    * Add `CloseableTransportInterface` to allow closing the transport
    88
    * Add `SentForRetryStamp` that identifies whether a failed message was sent for retry
    99
    * Add `Symfony\Component\Messenger\Middleware\DeduplicateMiddleware` and `Symfony\Component\Messenger\Stamp\DeduplicateStamp`
    10+
    * Add `--class-filter` option to the `messenger:failed:remove` command
    1011

    1112
    7.2
    1213
    ---

    src/Symfony/Component/Messenger/Command/FailedMessagesRemoveCommand.php

    Lines changed: 39 additions & 4 deletions
    Original file line numberDiff line numberDiff line change
    @@ -37,6 +37,7 @@ protected function configure(): void
    3737
    new InputOption('force', null, InputOption::VALUE_NONE, 'Force the operation without confirmation'),
    3838
    new InputOption('transport', null, InputOption::VALUE_OPTIONAL, 'Use a specific failure transport', self::DEFAULT_TRANSPORT_OPTION),
    3939
    new InputOption('show-messages', null, InputOption::VALUE_NONE, 'Display messages before removing it (if multiple ids are given)'),
    40+
    new InputOption('class-filter', null, InputOption::VALUE_REQUIRED, 'Filter by a specific class name'),
    4041
    ])
    4142
    ->setHelp(<<<'EOF'
    4243
    The <info>%command.name%</info> removes given messages that are pending in the failure transport.
    @@ -69,6 +70,24 @@ protected function execute(InputInterface $input, OutputInterface $output): int
    6970
    $shouldDeleteAllMessages = $input->getOption('all');
    7071

    7172
    $idsCount = \count($ids);
    73+
    74+
    if (!$receiver instanceof ListableReceiverInterface) {
    75+
    throw new RuntimeException(\sprintf('The "%s" receiver does not support removing specific messages.', $failureTransportName));
    76+
    }
    77+
    78+
    if (!$idsCount && null !== $input->getOption('class-filter')) {
    79+
    $ids = $this->getMessageIdsByClassFilter($input->getOption('class-filter'), $receiver);
    80+
    $idsCount = \count($ids);
    81+
    82+
    if (!$idsCount) {
    83+
    throw new RuntimeException('No failed messages were found with this filter.');
    84+
    }
    85+
    86+
    if (!$io->confirm(\sprintf('There is %d messages to remove. Do you want to continue?', $idsCount))) {
    87+
    return 0;
    88+
    }
    89+
    }
    90+
    7291
    if (!$shouldDeleteAllMessages && !$idsCount) {
    7392
    throw new RuntimeException('Please specify at least one message id. If you want to remove all failed messages, use the "--all" option.');
    7493
    } elseif ($shouldDeleteAllMessages && $idsCount) {
    @@ -77,10 +96,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
    7796

    7897
    $shouldDisplayMessages = $input->getOption('show-messages') || 1 === $idsCount;
    7998

    80-
    if (!$receiver instanceof ListableReceiverInterface) {
    81-
    throw new RuntimeException(\sprintf('The "%s" receiver does not support removing specific messages.', $failureTransportName));
    82-
    }
    83-
    8499
    if ($shouldDeleteAllMessages) {
    85100
    $this->removeAllMessages($receiver, $io, $shouldForce, $shouldDisplayMessages);
    86101
    } else {
    @@ -119,6 +134,26 @@ private function removeMessagesById(array $ids, ListableReceiverInterface $recei
    119134
    }
    120135
    }
    121136

    137+
    private function getMessageIdsByClassFilter(string $classFilter, ListableReceiverInterface $receiver): array
    138+
    {
    139+
    $ids = [];
    140+
    141+
    $this->phpSerializer?->acceptPhpIncompleteClass();
    142+
    try {
    143+
    foreach ($receiver->all() as $envelope) {
    144+
    if ($classFilter !== $envelope->getMessage()::class) {
    145+
    continue;
    146+
    }
    147+
    148+
    $ids[] = $this->getMessageId($envelope);
    149+
    };
    150+
    } finally {
    151+
    $this->phpSerializer?->rejectPhpIncompleteClass();
    152+
    }
    153+
    154+
    return $ids;
    155+
    }
    156+
    122157
    private function removeAllMessages(ListableReceiverInterface $receiver, SymfonyStyle $io, bool $shouldForce, bool $shouldDisplayMessages): void
    123158
    {
    124159
    if (!$shouldForce) {

    src/Symfony/Component/Messenger/Tests/Command/FailedMessagesRemoveCommandTest.php

    Lines changed: 47 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -182,6 +182,53 @@ public function testRemoveMultipleMessagesAndDisplayMessagesWithServiceLocator()
    182182
    $this->assertStringContainsString('Message with id 30 removed.', $tester->getDisplay());
    183183
    }
    184184

    185+
    public function testRemoveMessagesFilteredByClassMessage()
    186+
    {
    187+
    $globalFailureReceiverName = 'failure_receiver';
    188+
    $receiver = $this->createMock(ListableReceiverInterface::class);
    189+
    190+
    $anotherClass = new class extends \stdClass {};
    191+
    192+
    $series = [
    193+
    new Envelope(new \stdClass(), [new TransportMessageIdStamp(10)]),
    194+
    new Envelope(new $anotherClass(), [new TransportMessageIdStamp(20)]),
    195+
    new Envelope(new \stdClass(), [new TransportMessageIdStamp(30)]),
    196+
    ];
    197+
    $receiver->expects($this->once())->method('all')->willReturn($series);
    198+
    199+
    $expectedRemovedIds = [10, 30];
    200+
    $receiver->expects($this->exactly(2))->method('find')
    201+
    ->willReturnCallback(function (...$args) use ($series, &$expectedRemovedIds) {
    202+
    $expectedArgs = array_shift($expectedRemovedIds);
    203+
    $this->assertSame([$expectedArgs], $args);
    204+
    205+
    $return = array_filter(
    206+
    $series,
    207+
    static fn (Envelope $envelope) => [$envelope->last(TransportMessageIdStamp::class)->getId()] === $args,
    208+
    );
    209+
    210+
    return current($return);
    211+
    })
    212+
    ;
    213+
    214+
    $serviceLocator = $this->createMock(ServiceLocator::class);
    215+
    $serviceLocator->expects($this->once())->method('has')->with($globalFailureReceiverName)->willReturn(true);
    216+
    $serviceLocator->expects($this->any())->method('get')->with($globalFailureReceiverName)->willReturn($receiver);
    217+
    218+
    $command = new FailedMessagesRemoveCommand(
    219+
    $globalFailureReceiverName,
    220+
    $serviceLocator
    221+
    );
    222+
    223+
    $tester = new CommandTester($command);
    224+
    $tester->execute(['--class-filter' => "stdClass", '--force' => true, '--show-messages' => true]);
    225+
    226+
    $this->assertStringContainsString('There is 2 messages to remove. Do you want to continue? (yes/no)', $tester->getDisplay());
    227+
    $this->assertStringContainsString('Failed Message Details', $tester->getDisplay());
    228+
    $this->assertStringContainsString('Message with id 10 removed.', $tester->getDisplay());
    229+
    $this->assertStringContainsString('Message with id 30 removed.', $tester->getDisplay());
    230+
    }
    231+
    185232
    public function testCompletingTransport()
    186233
    {
    187234
    $globalFailureReceiverName = 'failure_receiver';

    0 commit comments

    Comments
     (0)
    0