8000 feature #36185 [Messenger] Add a \Throwable argument in RetryStrategy… · symfony/symfony@fdd8ac5 · GitHub
[go: up one dir, main page]

Skip to content

Commit fdd8ac5

Browse files
committed
feature #36185 [Messenger] Add a \Throwable argument in RetryStrategyInterface methods (Benjamin Dos Santos)
This PR was squashed before being merged into the 5.1-dev branch. Discussion ---------- [Messenger] Add a \Throwable argument in RetryStrategyInterface methods | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #36182 | License | MIT This allows to define new retry strategies based on the exceptions thrown during the last handling. Commits ------- 5fa9d68 [Messenger] Add a \Throwable argument in RetryStrategyInterface methods
2 parents 5aeecc2 + 5fa9d68 commit fdd8ac5

File tree

7 files changed

+61
-6
lines changed

7 files changed

+61
-6
lines changed

UPGRADE-5.1.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ Messenger
7373
* Deprecated Doctrine transport. It has moved to a separate package. Run `composer require symfony/doctrine-messenger` to use the new classes.
7474
* Deprecated RedisExt transport. It has moved to a separate package. Run `composer require symfony/redis-messenger` to use the new classes.
7575
* Deprecated use of invalid options in Redis and AMQP connections.
76+
* Deprecated *not* declaring a `\Throwable` argument in `RetryStrategyInterface::isRetryable()`
77+
* Deprecated *not* declaring a `\Throwable` argument in `RetryStrategyInterface::getWaitingTime()`
7678

7779
Notifier
7880
--------

UPGRADE-6.0.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ Messenger
6565
* Removed Doctrine transport. Run `composer require symfony/doctrine-messenger` to keep the transport in your application.
6666
* Removed RedisExt transport. Run `composer require symfony/redis-messenger` to keep the transport in your application.
6767
* Use of invalid options in Redis and AMQP connections now throws an error.
68+
* The signature of method `RetryStrategyInterface::isRetryable()` has been updated to `RetryStrategyInterface::isRetryable(Envelope $message, \Throwable $throwable = null)`.
69+
* The signature of method `RetryStrategyInterface::getWaitingTime()` has been updated to `RetryStrategyInterface::getWaitingTime(Envelope $message, \Throwable $throwable = null)`.
6870

6971
PhpUnitBridge
7072
-------------

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
* Moved AmqpExt transport to package `symfony/amqp-messenger`. All classes in `Symfony\Component\Messenger\Transport\AmqpExt` have been moved to `Symfony\Component\Messenger\Bridge\Amqp\Transport`
88
* Moved Doctrine transport to package `symfony/doctrine-messenger`. All classes in `Symfony\Component\Messenger\Transport\Doctrine` have been moved to `Symfony\Component\Messenger\Bridge\Doctrine\Transport`
99
* Moved RedisExt transport to package `symfony/redis-messenger`. All classes in `Symfony\Component\Messenger\Transport\RedisExt` have been moved to `Symfony\Component\Messenger\Bridge\Redis\Transport`
10+
* Added support for passing a `\Throwable` argument to `RetryStrategyInterface` methods. This allows to define strategies based on the reason of the handling failure.
1011

1112
5.0.0
1213
-----

src/Symfony/Component/Messenger/EventListener/SendFailedMessageForRetryListener.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ public function onMessageFailed(WorkerMessageFailedEvent $event)
5858
$event->setForRetry();
5959

6060
++$retryCount;
61-
$delay = $retryStrategy->getWaitingTime($envelope);
61+
62+
$delay = $retryStrategy->getWaitingTime($envelope, $throwable);
63+
6264
if (null !== $this->logger) {
6365
$this->logger->error('Error thrown while handling message {class}. Sending for retry #{retryCount} using {delay} ms delay. Error: "{error}"', $context + ['retryCount' => $retryCount, 'delay' => $delay, 'error' => $throwable->getMessage(), 'exception' => $throwable]);
6466
}
@@ -103,7 +105,7 @@ private function shouldRetry(\Throwable $e, Envelope $envelope, RetryStrategyInt
103105
return false;
104106
}
105107

106-
return $retryStrategy->isRetryable($envelope);
108+
return $retryStrategy->isRetryable($envelope, $e);
107109
}
108110

109111
private function getRetryStrategyForTransport(string $alias): ?RetryStrategyInterface

src/Symfony/Component/Messenger/Retry/MultiplierRetryStrategy.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,20 @@ public function __construct(int $maxRetries = 3, int $delayMilliseconds = 1000,
6363
$this->maxDelayMilliseconds = $maxDelayMilliseconds;
6464
}
6565

66-
public function isRetryable(Envelope $message): bool
66+
/**
67+
* @param \Throwable|null $throwable The cause of the failed handling
68+
*/
69+
public function isRetryable(Envelope $message, \Throwable $throwable = null): bool
6770
{
6871
$retries = RedeliveryStamp::getRetryCountFromEnvelope($message);
6972

7073
return $retries < $this->maxRetries;
7174
}
7275

73-
public function getWaitingTime(Envelope $message): int
76+
/**
77+
* @param \Throwable|null $throwable The cause of the failed handling
78+
*/
79+
public function getWaitingTime(Envelope $message, \Throwable $throwable = null): int
7480
{
7581
$retries = RedeliveryStamp::getRetryCountFromEnvelope($message);
7682

src/Symfony/Component/Messenger/Retry/RetryStrategyInterface.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,15 @@
2020
*/
2121
interface RetryStrategyInterface
2222
{
23-
public function isRetryable(Envelope $message): bool;
23+
/**
24+
* @param \Throwable|null $throwable The cause of the failed handling
25+
*/
26+
public function isRetryable(Envelope $message/*, \Throwable $throwable = null*/): bool;
2427

2528
/**
29+
* @param \Throwable|null $throwable The cause of the failed handling
30+
*
2631
* @return int The time to delay/wait in milliseconds
2732
*/
28-
public function getWaitingTime(Envelope $message): int;
33+
public function getWaitingTime(Envelope $message/*, \Throwable $throwable = null*/): int;
2934
}

src/Symfony/Component/Messenger/Tests/EventListener/SendFailedMessageForRetryListenerTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,41 @@ public function testEnvelopeIsSentToTransportOnRetry()
7676

7777
$listener->onMessageFailed($event);
7878
}
79+
80+
public function testEnvelopeIsSentToTransportOnRetryWithExceptionPassedToRetryStrategy()
81+
{
82+
$exception = new \Exception('no!');
83+
$envelope = new Envelope(new \stdClass());
84+
85+
$sender = $this->createMock(SenderInterface::class);
86+
$sender->expects($this->once())->method('send')->willReturnCallback(function (Envelope $envelope) {
87+
/** @var DelayStamp $delayStamp */
88+
$delayStamp = $envelope->last(DelayStamp::class);
89+
/** @var RedeliveryStamp $redeliveryStamp */
90+
$redeliveryStamp = $envelope->last(RedeliveryStamp::class);
91+
92+
$this->assertInstanceOf(DelayStamp::class, $delayStamp);
93+
$this->assertSame(1000, $delayStamp->getDelay());
94+
95+
$this->assertInstanceOf(RedeliveryStamp::class, $redeliveryStamp);
96+
$this->assertSame(1, $redeliveryStamp->getRetryCount());
97+
98+
return $envelope;
99+
});
100+
$senderLocator = $this->createMock(ContainerInterface::class);
101+
$senderLocator->expects($this->once())->method('has')->willReturn(true);
102+
$senderLocator->expects($this->once())->method('get')->willReturn($sender);
103+
$retryStategy = $this->createMock(RetryStrategyInterface::class);
104+
$retryStategy->expects($this->once())->method('isRetryable')->with($envelope, $exception)->willReturn(true);
105+
$retryStategy->expects($this->once())->method('getWaitingTime')->with($envelope, $exception)->willReturn(1000);
106+
$retryStrategyLocator = $this->createMock(ContainerInterface::class);
107+
$retryStrategyLocator->expects($this->once())->method('has')->willReturn(true);
108+
$retryStrategyLocator->expects($this->once())->method('get')->willReturn($retryStategy);
109+
110+
$listener = new SendFailedMessageForRetryListener($senderLocator, $retryStrategyLocator);
111+
112+
$event = new WorkerMessageFailedEvent($envelope, 'my_receiver', $exception);
113+
114+
$listener->onMessageFailed($event);
115+
}
79116
}

0 commit comments

Comments
 (0)
0