[Messenger] Fix exception message of failed message is dropped on retry
This commit is contained in:
parent
ad6dc2ec06
commit
8f9f44eb21
@ -13,12 +13,15 @@ namespace Symfony\Component\Messenger\Tests\Command;
|
|||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Symfony\Component\Console\Tester\CommandTester;
|
use Symfony\Component\Console\Tester\CommandTester;
|
||||||
|
use Symfony\Component\Debug\Exception\FlattenException;
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Component\Messenger\Command\FailedMessagesRetryCommand;
|
use Symfony\Component\Messenger\Command\FailedMessagesRetryCommand;
|
||||||
use Symfony\Component\Messenger\Envelope;
|
use Symfony\Component\Messenger\Envelope;
|
||||||
use Symfony\Component\Messenger\MessageBusInterface;
|
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\Transport\Receiver\ListableReceiverInterface;
|
||||||
use Symfony\Component\Messenger\Worker;
|
|
||||||
|
|
||||||
class FailedMessagesRetryCommandTest extends TestCase
|
class FailedMessagesRetryCommandTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -34,16 +37,52 @@ class FailedMessagesRetryCommandTest extends TestCase
|
|||||||
// the bus should be called in the worker
|
// the bus should be called in the worker
|
||||||
$bus->expects($this->exactly(2))->method('dispatch')->willReturn(new Envelope(new \stdClass()));
|
$bus->expects($this->exactly(2))->method('dispatch')->willReturn(new Envelope(new \stdClass()));
|
||||||
|
|
||||||
$command = new FailedMessagesRetryCommand(
|
$command = new FailedMessagesRetryCommand('failure_receiver', $receiver, $bus, $dispatcher);
|
||||||
'failure_receiver',
|
|
||||||
$receiver,
|
|
||||||
$bus,
|
|
||||||
$dispatcher
|
|
||||||
);
|
|
||||||
|
|
||||||
$tester = new CommandTester($command);
|
$tester = new CommandTester($command);
|
||||||
$tester->execute(['id' => [10, 12]]);
|
$tester->execute(['id' => [10, 12]]);
|
||||||
|
|
||||||
$this->assertStringContainsString('[OK]', $tester->getDisplay());
|
$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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace Symfony\Component\Messenger;
|
namespace Symfony\Component\Messenger;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Component\Debug\Exception\FlattenException;
|
||||||
use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent;
|
use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent;
|
||||||
use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;
|
use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;
|
||||||
use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent;
|
use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent;
|
||||||
@ -152,7 +153,7 @@ class Worker implements WorkerInterface
|
|||||||
|
|
||||||
// add the delay and retry stamp info + remove ReceivedStamp
|
// add the delay and retry stamp info + remove ReceivedStamp
|
||||||
$retryEnvelope = $envelope->with(new DelayStamp($delay))
|
$retryEnvelope = $envelope->with(new DelayStamp($delay))
|
||||||
->with(new RedeliveryStamp($retryCount, $transportName))
|
->with(new RedeliveryStamp($retryCount, $transportName, $throwable->getMessage(), $this->flattenedException($throwable)))
|
||||||
->withoutAll(ReceivedStamp::class);
|
->withoutAll(ReceivedStamp::class);
|
||||||
|
|
||||||
// re-send the message
|
// re-send the message
|
||||||
@ -215,4 +216,17 @@ class Worker implements WorkerInterface
|
|||||||
|
|
||||||
return $retryStrategy->isRetryable($envelope);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user