8000 [Messenger] Fix exception message of failed message is dropped on retry · symfony/symfony@8f9f44e · GitHub
[go: up one dir, main page]

Skip to content

Commit 8f9f44e

Browse files
committed
[Messenger] Fix exception message of failed message is dropped on retry
1 parent ad6dc2e commit 8f9f44e

File tree

2 files changed

+61
-8
lines changed

2 files changed

+61
-8
lines changed

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

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Console\Tester\CommandTester;
16+
use Symfony\Component\Debug\Exception\FlattenException;
1617
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
1718
use Symfony\Component\Messenger\Command\FailedMessagesRetryCommand;
1819
use Symfony\Component\Messenger\Envelope;
1920
use Symfony\Component\Messenger\MessageBusInterface;
21+
use Symfony\Component\Messenger\Retry\RetryStrategyInterface;
22+
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
23+
use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
2024
use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface;
21-
use Symfony\Component\Messenger\Worker;
2225

2326
class FailedMessagesRetryCommandTest extends TestCase
2427
{
@@ -34,16 +37,52 @@ public function testBasicRun()
3437
// the bus should be called in the worker
3538
$bus->expects($this->exactly(2))->method('dispatch')->willReturn(new Envelope(new \stdClass()));
3639

37-
$command = new FailedMessagesRetryCommand(
38-
'failure_receiver',
39-
$receiver,
40-
$bus,
41-
$dispatcher
42-
);
40+
$command = new FailedMessagesRetryCommand('failure_receiver', $receiver, $bus, $dispatcher);
4341

4442
$tester = new CommandTester($command);
4543
$tester->execute(['id' => [10, 12]]);
4644

4745
$this->assertStringContainsString('[OK]', $tester->getDisplay());
4846
}
47+
48+
public function testExceptionOnRetry()
49+
{
50+
$receiver = $this->createMock(ListableReceiverInterface::class);
51+
$receiver->expects($this->once())->method('find')->with(10)->willReturn(new Envelope(new \stdClass()));
52+
// message will eventually be ack'ed in Worker
53+
$receiver->expects($this->once())->method('ack');
54+
55+
$dispatcher = $this->createMock(EventDispatcherInterface::class);
56+
$bus = $this->createMock(MessageBusInterface::class);
57+
// the bus should be called in the worker
58+
$bus->expects($this->at(0))
59+
->method('dispatch')
60+
->with($this->callback(function (Envelope $envelope) {
61+
$lastReceivedStamp = $envelope->last(ReceivedStamp::class);
62+
63+
return $lastReceivedStamp instanceof ReceivedStamp && \is_string($lastReceivedStamp->getTransportName());
64+
}))
65+
->will($this->throwException(new \Exception('Mock test exception')));
66+
67+
$bus->expects($this->at(1))
68+
->method('dispatch')
69+
->with($this->callback(function (Envelope $envelope) {
70+
$lastRedeliveryStamp = $envelope->last(RedeliveryStamp::class);
71+
72+
return $lastRedeliveryStamp instanceof RedeliveryStamp &&
73+
\is_string($lastRedeliveryStamp->getExceptionMessage()) &&
74+
$lastRedeliveryStamp->getFlattenException() instanceof FlattenException;
75+
}))
76+
->willReturn(new Envelope(new \stdClass()));
77+
78+
$retryStrategy = $this->createMock(RetryStrategyInterface::class);
79+
$retryStrategy->expects($this->once())->method('isRetryable')->with($this->isInstanceOf(Envelope::class))->willReturn(true);
80+
81+
$command = new FailedMessagesRetryCommand('failure_receiver', $receiver, $bus, $dispatcher, $retryStrategy);
82+
83+
$tester = new CommandTester($command);
84+
$tester->execute(['id' => [10]]);
85+
86+
$this->assertStringContainsString('[OK]', $tester->getDisplay());
87+
}
4988
}

src/Symfony/Component/Messenger/Worker.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Messenger;
1313

1414
use Psr\Log\LoggerInterface;
15+
use Symfony\Component\Debug\Exception\FlattenException;
1516
use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent;
1617
use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;
1718
use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent;
@@ -152,7 +153,7 @@ private function handleMessage(Envelope $envelope, ReceiverInterface $receiver,
152153

153154
// add the delay and retry stamp info + remove ReceivedStamp
154155
$retryEnvelope = $envelope->with(new DelayStamp($delay))
155-
->with(new RedeliveryStamp($retryCount, $transportName))
156+
->with(new RedeliveryStamp($retryCount, $transportName, $throwable->getMessage(), $this->flattenedException($throwable)))
156157
->withoutAll(ReceivedStamp::class);
157158

158159
// re-send the message
@@ -215,4 +216,17 @@ private function shouldRetry(\Throwable $e, Envelope $envelope, RetryStrategyInt
215216

216217
return $retryStrategy->isRetryable($envelope);
217218
}
219+
220+
private function flattenedException(\Throwable $throwable): ?FlattenException
221+
{
222+
if (!class_exists(FlattenException::class)) {
223+
return null;
224+
}
225+
226+
if ($throwable instanceof HandlerFailedException) {
227+
$throwable = $throwable->getNestedExceptions()[0];
228+
}
229+
230+
return FlattenException::createFromThrowable($throwable);
231+
}
218232
}

0 commit comments

Comments
 (0)
0