Skip to content

Commit

Permalink
[Messenger] Fix exception message of failed message is dropped on retry
Browse files Browse the repository at this point in the history
  • Loading branch information
tienvx committed Sep 17, 2019
1 parent ad6dc2e commit 8f9f44e
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 8 deletions.
Expand Up @@ -13,12 +13,15 @@

use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Messenger\Command\FailedMessagesRetryCommand;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Messenger\Retry\RetryStrategyInterface;
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface;
use Symfony\Component\Messenger\Worker;

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

$command = new FailedMessagesRetryCommand(
'failure_receiver',
$receiver,
$bus,
$dispatcher
);
$command = new FailedMessagesRetryCommand('failure_receiver', $receiver, $bus, $dispatcher);

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

$this->assertStringContainsString('[OK]', $tester->getDisplay());
}

public function testExceptionOnRetry()
{
$receiver = $this->createMock(ListableReceiverInterface::class);
$receiver->expects($this->once())->method('find')->with(10)->willReturn(new Envelope(new \stdClass()));
// message will eventually be ack'ed in Worker
$receiver->expects($this->once())->method('ack');

$dispatcher = $this->createMock(EventDispatcherInterface::class);
$bus = $this->createMock(MessageBusInterface::class);
// the bus should be called in the worker
$bus->expects($this->at(0))
->method('dispatch')
->with($this->callback(function (Envelope $envelope) {
$lastReceivedStamp = $envelope->last(ReceivedStamp::class);

return $lastReceivedStamp instanceof ReceivedStamp && \is_string($lastReceivedStamp->getTransportName());
}))
->will($this->throwException(new \Exception('Mock test exception')));

$bus->expects($this->at(1))
->method('dispatch')
->with($this->callback(function (Envelope $envelope) {
$lastRedeliveryStamp = $envelope->last(RedeliveryStamp::class);

return $lastRedeliveryStamp instanceof RedeliveryStamp &&
\is_string($lastRedeliveryStamp->getExceptionMessage()) &&
$lastRedeliveryStamp->getFlattenException() instanceof FlattenException;
}))
->willReturn(new Envelope(new \stdClass()));

$retryStrategy = $this->createMock(RetryStrategyInterface::class);
$retryStrategy->expects($this->once())->method('isRetryable')->with($this->isInstanceOf(Envelope::class))->willReturn(true);

$command = new FailedMessagesRetryCommand('failure_receiver', $receiver, $bus, $dispatcher, $retryStrategy);

$tester = new CommandTester($command);
$tester->execute(['id' => [10]]);

$this->assertStringContainsString('[OK]', $tester->getDisplay());
}
}
16 changes: 15 additions & 1 deletion src/Symfony/Component/Messenger/Worker.php
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\Messenger;

use Psr\Log\LoggerInterface;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent;
use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;
use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent;
Expand Down Expand Up @@ -152,7 +153,7 @@ private function handleMessage(Envelope $envelope, ReceiverInterface $receiver,

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

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

return $retryStrategy->isRetryable($envelope);
}

private function flattenedException(\Throwable $throwable): ?FlattenException
{
if (!class_exists(FlattenException::class)) {
return null;
}

if ($throwable instanceof HandlerFailedException) {
$throwable = $throwable->getNestedExceptions()[0];
}

return FlattenException::createFromThrowable($throwable);
}
}

0 comments on commit 8f9f44e

Please sign in to comment.