* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Messenger\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\Dumper; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Stamp\RedeliveryStamp; use Symfony\Component\Messenger\Stamp\SentToFailureTransportStamp; use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp; use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface; use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; /** * @author Ryan Weaver * * @internal */ abstract class AbstractFailedMessagesCommand extends Command { private $receiverName; private $receiver; public function __construct(string $receiverName, ReceiverInterface $receiver) { $this->receiverName = $receiverName; $this->receiver = $receiver; parent::__construct(); } protected function getReceiverName(): string { return $this->receiverName; } /** * @return mixed */ protected function getMessageId(Envelope $envelope) { /** @var TransportMessageIdStamp $stamp */ $stamp = $envelope->last(TransportMessageIdStamp::class); return null !== $stamp ? $stamp->getId() : null; } protected function displaySingleMessage(Envelope $envelope, SymfonyStyle $io) { $io->title('Failed Message Details'); /** @var SentToFailureTransportStamp|null $sentToFailureTransportStamp */ $sentToFailureTransportStamp = $envelope->last(SentToFailureTransportStamp::class); $lastRedeliveryStampWithException = $this->getLastRedeliveryStampWithException($envelope); $rows = [ ['Class', \get_class($envelope->getMessage())], ]; if (null !== $id = $this->getMessageId($envelope)) { $rows[] = ['Message Id', $id]; } $flattenException = null === $lastRedeliveryStampWithException ? null : $lastRedeliveryStampWithException->getFlattenException(); if (null === $sentToFailureTransportStamp) { $io->warning('Message does not appear to have been sent to this transport after failing'); } else { $rows = array_merge($rows, [ ['Failed at', null === $lastRedeliveryStampWithException ? '' : $lastRedeliveryStampWithException->getRedeliveredAt()->format('Y-m-d H:i:s')], ['Error', null === $lastRedeliveryStampWithException ? '' : $lastRedeliveryStampWithException->getExceptionMessage()], ['Error Class', null === $flattenException ? '(unknown)' : $flattenException->getClass()], ['Transport', $sentToFailureTransportStamp->getOriginalReceiverName()], ]); } $io->table([], $rows); /** @var RedeliveryStamp[] $redeliveryStamps */ $redeliveryStamps = $envelope->all(RedeliveryStamp::class); $io->writeln(' Message history:'); foreach ($redeliveryStamps as $redeliveryStamp) { $io->writeln(sprintf(' * Message failed at %s and was redelivered', $redeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s'))); } $io->newLine(); if ($io->isVeryVerbose()) { $io->title('Message:'); $dump = new Dumper($io); $io->writeln($dump($envelope->getMessage())); $io->title('Exception:'); $io->writeln(null === $flattenException ? '(no data)' : $flattenException->getTraceAsString()); } else { $io->writeln(' Re-run command with -vv to see more message & error details.'); } } protected function printPendingMessagesMessage(ReceiverInterface $receiver, SymfonyStyle $io) { if ($receiver instanceof MessageCountAwareInterface) { if (1 === $receiver->getMessageCount()) { $io->writeln('There is 1 message pending in the failure transport.'); } else { $io->writeln(sprintf('There are %d messages pending in the failure transport.', $receiver->getMessageCount())); } } } protected function getReceiver(): ReceiverInterface { return $this->receiver; } protected function getLastRedeliveryStampWithException(Envelope $envelope): ?RedeliveryStamp { /** @var RedeliveryStamp $stamp */ foreach (array_reverse($envelope->all(RedeliveryStamp::class)) as $stamp) { if (null !== $stamp->getExceptionMessage()) { return $stamp; } } return null; } }