From 8fc3dcc45d37ba5daaea5549d228cfd10adfb506 Mon Sep 17 00:00:00 2001 From: Alexander Grimalovsky Date: Sun, 22 Jan 2023 15:38:39 +0300 Subject: [PATCH] [Messenger] Respect `isRetryable` decision of the retry strategy when deciding if failed message should be re-delivered --- .../SendFailedMessageForRetryListener.php | 7 +++--- .../SendFailedMessageForRetryListenerTest.php | 23 ++++++++++++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Messenger/EventListener/SendFailedMessageForRetryListener.php b/src/Symfony/Component/Messenger/EventListener/SendFailedMessageForRetryListener.php index dab74b203f795..ddd7f1b1f61b0 100644 --- a/src/Symfony/Component/Messenger/EventListener/SendFailedMessageForRetryListener.php +++ b/src/Symfony/Component/Messenger/EventListener/SendFailedMessageForRetryListener.php @@ -123,7 +123,8 @@ public static function getSubscribedEvents() private function shouldRetry(\Throwable $e, Envelope $envelope, RetryStrategyInterface $retryStrategy): bool { - if ($e instanceof RecoverableExceptionInterface) { + $isRetryable = $retryStrategy->isRetryable($envelope, $e); + if ($isRetryable && $e instanceof RecoverableExceptionInterface) { return true; } @@ -132,7 +133,7 @@ private function shouldRetry(\Throwable $e, Envelope $envelope, RetryStrategyInt if ($e instanceof HandlerFailedException) { $shouldNotRetry = true; foreach ($e->getNestedExceptions() as $nestedException) { - if ($nestedException instanceof RecoverableExceptionInterface) { + if ($isRetryable && $nestedException instanceof RecoverableExceptionInterface) { return true; } @@ -150,7 +151,7 @@ private function shouldRetry(\Throwable $e, Envelope $envelope, RetryStrategyInt return false; } - return $retryStrategy->isRetryable($envelope, $e); + return $isRetryable; } private function getRetryStrategyForTransport(string $alias): ?RetryStrategyInterface diff --git a/src/Symfony/Component/Messenger/Tests/EventListener/SendFailedMessageForRetryListenerTest.php b/src/Symfony/Component/Messenger/Tests/EventListener/SendFailedMessageForRetryListenerTest.php index a5fe10e85578b..8d795d7b86c23 100644 --- a/src/Symfony/Component/Messenger/Tests/EventListener/SendFailedMessageForRetryListenerTest.php +++ b/src/Symfony/Component/Messenger/Tests/EventListener/SendFailedMessageForRetryListenerTest.php @@ -63,7 +63,7 @@ public function testRecoverableStrategyCausesRetry() $senderLocator->expects($this->once())->method('has')->willReturn(true); $senderLocator->expects($this->once())->method('get')->willReturn($sender); $retryStategy = $this->createMock(RetryStrategyInterface::class); - $retryStategy->expects($this->never())->method('isRetryable'); + $retryStategy->expects($this->once())->method('isRetryable')->willReturn(true); $retryStategy->expects($this->once())->method('getWaitingTime')->willReturn(1000); $retryStrategyLocator = $this->createMock(ContainerInterface::class); $retryStrategyLocator->expects($this->once())->method('has')->willReturn(true); @@ -78,6 +78,27 @@ public function testRecoverableStrategyCausesRetry() $listener->onMessageFailed($event); } + public function testRetryIsOnlyAllowedWhenPermittedByRetryStrategy() + { + $senderLocator = $this->createMock(ContainerInterface::class); + $senderLocator->expects($this->never())->method('has'); + $senderLocator->expects($this->never())->method('get'); + $retryStrategy = $this->createMock(RetryStrategyInterface::class); + $retryStrategy->expects($this->once())->method('isRetryable')->willReturn(false); + $retryStrategy->expects($this->never())->method('getWaitingTime'); + $retryStrategyLocator = $this->createMock(ContainerInterface::class); + $retryStrategyLocator->expects($this->once())->method('has')->willReturn(true); + $retryStrategyLocator->expects($this->once())->method('get')->willReturn($retryStrategy); + + $listener = new SendFailedMessageForRetryListener($senderLocator, $retryStrategyLocator); + + $exception = new RecoverableMessageHandlingException('retry'); + $envelope = new Envelope(new \stdClass()); + $event = new WorkerMessageFailedEvent($envelope, 'my_receiver', $exception); + + $listener->onMessageFailed($event); + } + public function testEnvelopeIsSentToTransportOnRetry() { $exception = new \Exception('no!');