8000 feature #39622 [Messenger] Be able to get raw data when a message in … · symfony/symfony@e788a49 · GitHub
[go: up one dir, main page]

Skip to content

Commit e788a49

Browse files
committed
feature #39622 [Messenger] Be able to get raw data when a message in not decodable by the PHP Serializer (lyrixx)
This PR was merged into the 6.2 branch. Discussion ---------- [Messenger] Be able to get raw data when a message in not decodable by the PHP Serializer | Q | A | ------------- | --- | Branch? | 6.2 | Bug fix? | yes | New feature? | yes | Deprecations? | no | Tickets | | License | MIT | Doc PR | --- It's easier to review the pr with [`?w=1`](https://github.com/symfony/symfony/pull/39622/files?w=1) --- ## Why? This PR aimed to handle properly messaged that are already failed and also **not decodable** anymore. This use case occurs when a Message class is renamed / moved to another namespace ## Reproducer 1. Publish many message of type `App\Message\Foobar` 1. Consume them all, but throw an Exception exception in the handler 1. Renamed `Foobar` to `Foo` ## Before / After ### command `messenger:failed:show` #### Before ##### Without an ID ``` …abs/symfony/messenger-class-not-found(new) bin/console messenger:failed:show There are 94 messages pending in the failure transport. In PhpSerializer.php line 84: Message class "App\Message\Foobar" not found during decoding. messenger:failed:show [--max MAX] [--transport [TRANSPORT]] [--stats] [--class-filter CLASS-FILTER] [--] [<id>] ``` And this **message is lost** ##### With an ID ``` >…abs/symfony/messenger-class-not-found(new) bin/console messenger:failed:show 68 There are 93 messages pending in the failure transport. In PhpSerializer.php line 84: Message class "App\Message\Foobar" not found during decoding. messenger:failed:show [--max MAX] [--transport [TRANSPORT]] [--stats] [--class-filter CLASS-FILTER] [--] [<id>] ``` **Message lost too** #### After ##### Without an ID ``` >…goire/dev/labs/symfony/symfony-5.2(remaned) bin/console messenger:failed:show There are 94 messages pending in the failure transport. ----- ------------------------ --------------------- --------------------------------------- Id Class Failed at Error ----- ------------------------ --------------------- --------------------------------------- 62 __PHP_Incomplete_Class 2022-08-12 16:26:06 FoobarHandler is not implemented yet. 63 __PHP_Incomplete_Class 2022-08-12 16:26:06 FoobarHandler is not implemented yet. 64 __PHP_Incomplete_Class 2022-08-12 16:26:06 FoobarHandler is not implemented yet. // Showing first 50 messages. // Run messenger:failed:show {id} --transport=failed -vv to see message details. ``` **No messages are lost** ##### With an ID ``` >…abs/symfony/messenger-class-not-found(new) bin/console messenger:failed:show 69 There are 92 messages pending in the failure transport. Failed Message Details ====================== ------------- --------------------------------------- Class __PHP_Incomplete_Class Message Id 69 Failed at 2022-08-12 16:26:06 Error FoobarHandler is not implemented yet. Error Code 0 Error Class Exception Transport async ------------- --------------------------------------- Message history: * Message failed at 2022-08-12 16:25:58 and was redelivered * Message failed at 2022-08-12 16:25:59 and was redelivered * Message failed at 2022-08-12 16:26:02 and was redelivered * Message failed at 2022-08-12 16:26:06 and was redelivered [ERROR] The message could not be decoded. Re-run command with -vv to see more message & error details. Run messenger:failed:retry 69 --transport=failed to retry this message. Run messenger:failed:remove 69 --transport=failed to delete it. ``` **messages not lost** ##### With an ID an -vv ``` >…abs/symfony/messenger-class-not-found(new) bin/console messenger:failed:show 69 -vv There are 92 messages pending in the failure transport. Failed Message Details ====================== ------------- --------------------------------------- Class __PHP_Incomplete_Class Message Id 69 Failed at 2022-08-12 16:26:06 Error FoobarHandler is not implemented yet. Error Code 0 Error Class Exception Transport async ------------- --------------------------------------- Message history: * Message failed at 2022-08-12 16:25:58 and was redelivered * Message failed at 2022-08-12 16:25:59 and was redelivered * Message failed at 2022-08-12 16:26:02 and was redelivered * Message failed at 2022-08-12 16:26:06 and was redelivered Message: ======== [ERROR] The message could not be decoded. See below an APPROXIMATIVE representation of the class. __PHP_Incomplete_Class(App\Message\Foobar) {} Exception: ========== Exception^ { message: "FoobarHandler is not implemented yet." code: 0 file: "/home/gregoire/dev/labs/symfony/messenger-class-not-found/src/MessageHandler/FoobarHandler.php" line: 12 trace: { /home/gregoire/dev/labs/symfony/messenger-class-not-found/src/MessageHandler/FoobarHandler.php:12 /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php:95 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php:71 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Messenger/Middleware/FailedMessageProcessingMiddleware.php:34 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Messenger/Middleware/DispatchAfterCurrentBusMiddleware.php:68 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Messenger/Middleware/RejectRedeliveredMessageMiddleware.php:41 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Messenger/Middleware/AddBusNameStampMiddleware.php:37 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Messenger/Middleware/TraceableMiddleware.php:43 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Messenger/MessageBus.php:73 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Messenger/TraceableMessageBus.php:41 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Messenger/RoutableMessageBus.php:54 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Messenger/Worker.php:156 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Messenger/Worker.php:105 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php:223 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Console/Command/Command.php:309 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Console/Application.php:1019 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php:94 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Console/Application.php:300 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php:80 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Console/Application.php:172 { …} /home/gregoire/dev/github.com/lyrixx/symfony/src/Symfony/Component/Runtime/Runner/Symfony/ConsoleApplicationRunner.php:54 { …} ./vendor/autoload_runtime.php:29 { …} ./bin/console:11 { …} } } Run messenger:failed:retry 69 --transport=failed to retry this message. Run messenger:failed:remove 69 --transport=failed to delete it. ``` <details> <summary>screenshot with colors</summary> ![screenshot with colors](https://user-images.githubusercontent.com/408368/187463971-a5464683-f826-4dcb-a2c2-79f91cb00bc0.png) </details> **messages not lost** ### command `messenger:failed:retry` #### Before ``` >…abs/symfony/messenger-class-not-found(new) bin/console messenger:failed:retry 69 // Quit this command with CONTROL-C. // Re-run the command with a -vv option to see logs about consumed messages. There are 92 messages pending in the failure transport. To retry all the messages, run messenger:consume failed In PhpSerializer.php line 84: Message class "App\Message\Foobar" not found during decoding. messenger:failed:retry [--force] [--transport [TRANSPORT]] [--] [<id>...] ``` **And the first message is lost** Same if I use an ID #### After ##### Without ID ``` >…abs/symfony/messenger-class-not-found(new) bin/console messenger:failed:retry // Quit this command with CONTROL-C. // Re-run the command with a -vv option to see logs about consumed messages. There are 91 messages pending in the failure transport. To retry all the messages, run messenger:consume failed Failed Message Details ====================== ------------- --------------------------------------- Class __PHP_Incomplete_Class Message Id 63 Failed at 2022-08-12 16:26:06 Error FoobarHandler is not implemented yet. Error Code 0 Error Class Exception Transport async ------------- --------------------------------------- Message history: * Message failed at 2022-08-12 16:25:58 and was redelivered * Message failed at 2022-08-12 16:25:59 and was redelivered * Message failed at 2022-08-12 16:26:02 and was redelivered * Message failed at 2022-08-12 16:26:06 and was redelivered [ERROR] The message could not be decoded. Re-run command with -vv to see more message & error details. In FailedMessagesRetryCommand.php line 176: The message with id "63" could not decoded, it can only be shown or removed. messenger:failed:retry [--force] [--transport [TRANSPORT]] [--] [<id>...] ``` **And the message is not lost** ##### With an ID ``` >…abs/symfony/messenger-class-not-found(new) bin/console messenger:failed:retry 63 // Quit this command with CONTROL-C. // Re-run the command with a -vv option to see logs about consumed messages. There are 91 messages pending in the failure transport. To retry all the messages, run messenger:consume failed Failed Message Details ====================== ------------- --------------------------------------- Class __PHP_Incomplete_Class Message Id 63 Failed at 2022-08-12 16:26:06 Error FoobarHandler is not implemented yet. Error Code 0 Error Class Exception Transport async ------------- --------------------------------------- Message history: * Message failed at 2022-08-12 16:25:58 and was redelivered * Message failed at 2022-08-12 16:25:59 and was redelivered * Message failed at 2022-08-12 16:26:02 and was redelivered * Message failed at 2022-08-12 16:26:06 and was redelivered [ERROR] The message could not be decoded. Re-run command with -vv to see more message & error details. In FailedMessagesRetryCommand.php line 176: The message with id "63" could not decoded, it can only be shown or removed. messenger:failed:retry [--force] [--transport [TRANSPORT]] [--] [<id>...] ``` ### command `messenger:failed:remove` #### Before ``` >…abs/symfony/messenger-class-not-found(new) bin/console messenger:failed:remove 63 In PhpSerializer.php line 84: Message class "App\Message\Foobar" not found during decoding. messenger:failed:remove [--force] [--transport [TRANSPORT]] [--show-messages] [--] <id>... ``` The message is lost, but it's not an issue I guess :p #### After ``` >…abs/symfony/messenger-class-not-found(new) bin/console messenger:failed:remove 69 [ERROR] The message with id "69" was not found. >…abs/symfony/messenger-class-not-found(new) bin/console messenger:failed:remove 79 Failed Message Details ====================== ------------- --------------------------------------- Class __PHP_Incomplete_Class Message Id 79 Failed at 2022-08-12 16:26:06 Error FoobarHandler is not implemented yet. Error Code 0 Error Class Exception Transport async ------------- --------------------------------------- Message history: * Message failed at 2022-08-12 16:25:58 and was redelivered * Message failed at 2022-08-12 16:25:59 and was redelivered * Message failed at 2022-08-12 16:26:02 and was redelivered * Message failed at 2022-08-12 16:26:06 and was redelivered [ERROR] The message could not be decoded. Re-run command with -vv to see more message & error details. Do you want to permanently remove this message? (yes/no) [no]: > yes [OK] Message with id 79 removed. ``` --- ## Extra ### `messenger:consume` command This command is not fixed on purpose: We keep the default behavior to keep a BC. **BUT** I would like to use the same stamp system I introduce to avoid loosing a message. Because ATM, when a DecodeException is thrown, the message is lost. Not cool! ``` >…goire/dev/labs/symfony/symfony-5.2(remaned) bin/console messenger:consume failed [OK] Consuming messages from transports "failed". // The worker will automatically exit once it has received a stop signal via the messenger:stop-workers command. // Quit the worker with CONTROL-C. // Re-run the command with a -vv option to see logs about consumed messages. In PhpSerializer.php line 92: Message class "App\Message\Foobar" not found during decoding. ``` Commits ------- 34229af [Messenger] Be able to get raw data when a message in not decodable by the PHP Serializer
2 parents 0be39ad + 34229af commit e788a49

File tree

9 files changed

+225
-56
lines changed

9 files changed

+225
-56
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/console.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,20 +191,23 @@
191191
service('messenger.routable_message_bus'),
192192
service('event_dispatcher'),
193193
service('logger'),
194+
service('messenger.transport.native_php_serializer')->nullOnInvalid(),
194195
])
195196
->tag('console.command')
196197

197198
->set('console.command.messenger_failed_messages_show', FailedMessagesShowCommand::class)
198199
->args([
199200
abstract_arg('Default failure receiver name'),
200201
abstract_arg('Receivers'),
202+
service('messenger.transport.native_php_serializer')->nullOnInvalid(),
201203
])
202204
->tag('console.command')
203205

204206
->set('console.command.messenger_failed_messages_remove', FailedMessagesRemoveCommand::class)
205207
->args([
206208
abstract_arg('Default failure receiver name'),
207209
abstract_arg('Receivers'),
210+
service('messenger.transport.native_php_serializer')->nullOnInvalid(),
208211
])
209212
->tag('console.command')
210213

src/Symfony/Component/Messenger/Command/AbstractFailedMessagesCommand.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@
2121
use Symfony\Component\Messenger\Envelope;
2222
use Symfony\Component\Messenger\Exception\InvalidArgumentException;
2323
use Symfony\Component\Messenger\Stamp\ErrorDetailsStamp;
24+
use Symfony\Component\Messenger\Stamp\MessageDecodingFailedStamp;
2425
use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
2526
use Symfony\Component\Messenger\Stamp\SentToFailureTransportStamp;
2627
use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp;
2728
use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface;
2829
use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface;
2930
use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface;
31+
use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer;
3032
use Symfony\Component\VarDumper\Caster\Caster;
3133
use Symfony\Component\VarDumper\Caster\TraceStub;
3234
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
@@ -44,13 +46,15 @@ abstract class AbstractFailedMessagesCommand extends Command
4446
protected const DEFAULT_TRANSPORT_OPTION = 'choose';
4547

4648
protected $failureTransports;
49+
protected ?PhpSerializer $phpSerializer;
4750

4851
private ?string $globalFailureReceiverName;
4952

50-
public function __construct(?string $globalFailureReceiverName, ServiceProviderInterface $failureTransports)
53+
public function __construct(?string $globalFailureReceiverName, ServiceProviderInterface $failureTransports, PhpSerializer $phpSerializer = null)
5154
{
5255
$this->failureTransports = $failureTransports;
5356
$this->globalFailureReceiverName = $globalFailureReceiverName;
57+
$this->phpSerializer = $phpSerializer;
5458

5559
parent::__construct();
5660
}
@@ -78,6 +82,8 @@ protected function displaySingleMessage(Envelope $envelope, SymfonyStyle $io)
7882
$lastRedeliveryStamp = $envelope->last(RedeliveryStamp::class);
7983
/** @var ErrorDetailsStamp|null $lastErrorDetailsStamp */
8084
$lastErrorDetailsStamp = $envelope->last(ErrorDetailsStamp::class);
85+
/** @var MessageDecodingFailedStamp|null $lastMessageDecodingFailedStamp */
86+
$lastMessageDecodingFailedStamp = $envelope->last(MessageDecodingFailedStamp::class);
8187

8288
$rows = [
8389
['Class', \get_class($envelope->getMessage())],
@@ -126,12 +132,18 @@ protected function displaySingleMessage(Envelope $envelope, SymfonyStyle $io)
126132

127133
if ($io->isVeryVerbose()) {
128134
$io->title('Message:');
135+
if (null !== $lastMessageDecodingFailedStamp) {
136+
$io->error('The message could not be decoded. See below an APPROXIMATIVE representation of the class.');
137+
}
129138
$dump = new Dumper($io, null, $this->createCloner());
130139
$io->writeln($dump($envelope->getMessage()));
131140
$io->title('Exception:');
132141
$flattenException = $lastErrorDetailsStamp?->getFlattenException();
133142
$io->writeln(null === $flattenException ? '(no data)' : $dump($flattenException));
134143
} else {
144+
if (null !== $lastMessageDecodingFailedStamp) {
145+
$io->error('The message could not be decoded.');
146+
}
135147
$io->writeln(' Re-run command with <info>-vv</info> to see more message & error details.');
136148
}
137149
}

src/Symfony/Component/Messenger/Command/FailedMessagesRemoveCommand.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,13 @@ private function removeMessages(string $failureTransportName, array $ids, Receiv
7474
}
7575

7676
foreach ($ids as $id) {
77-
$envelope = $receiver->find($id);
77+
$this->phpSerializer?->enableClassNotFoundCreation();
78+
try {
79+
$envelope = $receiver->find($id);
80+
} finally {
81+
$this->phpSerializer?->enableClassNotFoundCreation(false);
82+
}
83+
7884
if (null === $envelope) {
7985
$io->error(sprintf('The message with id "%s" was not found.', $id));
8086
continue;

src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@
2323
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
2424
use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent;
2525
use Symfony\Component\Messenger\EventListener\StopWorkerOnMessageLimitListener;
26-
use Symfony\Component\Messenger\Exception\LogicException;
2726
use Symfony\Component\Messenger\MessageBusInterface;
27+
use Symfony\Component\Messenger\Stamp\MessageDecodingFailedStamp;
2828
use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface;
2929
use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface;
3030
use Symfony\Component\Messenger\Transport\Receiver\SingleMessageReceiver;
31+
use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer;
3132
use Symfony\Component\Messenger\Worker;
3233
use Symfony\Contracts\Service\ServiceProviderInterface;
3334

@@ -41,13 +42,13 @@ class FailedMessagesRetryCommand extends AbstractFailedMessagesCommand
4142
private MessageBusInterface $messageBus;
4243
private ?LoggerInterface $logger;
4344

44-
public function __construct(?string $globalReceiverName, ServiceProviderInterface $failureTransports, MessageBusInterface $messageBus, EventDispatcherInterface $eventDispatcher, LoggerInterface $logger = null)
45+
public function __construct(?string $globalReceiverName, ServiceProviderInterface $failureTransports, MessageBusInterface $messageBus, EventDispatcherInterface $eventDispatcher, LoggerInterface $logger = null, PhpSerializer $phpSerializer = null)
4546
{
4647
$this->eventDispatcher = $eventDispatcher;
4748
$this->messageBus = $messageBus;
4849
$this->logger = $logger;
4950

50-
parent::__construct($globalReceiverName, $failureTransports);
51+
parent::__construct($globalReceiverName, $failureTransports, $phpSerializer);
5152
}
5253

5354
protected function configure(): void
@@ -133,23 +134,23 @@ private function runInteractive(string $failureTransportName, SymfonyStyle $io,
133134
// to be temporarily "acked", even if the user aborts
134135
// handling the message
135136
while (true) {
136-
$ids = [];
137-
foreach ($receiver->all(1) as $envelope) {
138-
++$count;
139-
140-
$id = $this->getMessageId($envelope);
141-
if (null === $id) {
142-
throw new LogicException(sprintf('The "%s" receiver is able to list messages by id but the envelope is missing the TransportMessageIdStamp stamp.', $failureTransportName));
137+
$envelopes = [];
138+
$this->phpSerializer?->enableClassNotFoundCreation();
139+
try {
140+
foreach ($receiver->all(1) as $envelope) {
141+
++$count;
142+
$envelopes[] = $envelope;
143143
}
144-
$ids[] = $id;
144+
} finally {
145+
$this->phpSerializer?->enableClassNotFoundCreation(false);
145146
}
146147

147148
// break the loop if all messages are consumed
148-
if (0 === \count($ids)) {
149+
if (0 === \count($envelopes)) {
149150
break;
150151
}
151152

152-
$this->retrySpecificIds($failureTransportName, $ids, $io, $shouldForce);
153+
$this->retrySpecificEnvelops($envelopes, $failureTransportName, $io, $shouldForce);
153154
}
154155
} else {
155156
// get() and ask messages one-by-one
@@ -171,6 +172,10 @@ private function runWorker(string $failureTransportName, ReceiverInterface $rece
171172

172173
$this->displaySingleMessage($envelope, $io);
173174

175+
if ($envelope->last(MessageDecodingFailedStamp::class)) {
176+
throw new \RuntimeException(sprintf('The message with id "%s" could not decoded, it can only be shown or removed.', $this->getMessageId($envelope) ?? '?'));
177+
}
178+
174179
$shouldHandle = $shouldForce || $io->confirm('Do you want to retry (yes) or delete this message (no)?');
175180

176181
if ($shouldHandle) {
@@ -207,7 +212,12 @@ private function retrySpecificIds(string $failureTransportName, array $ids, Symf
207212
}
208213

209214
foreach ($ids as $id) {
210-
$envelope = $receiver->find($id);
215+
$this->phpSerializer?->enableClassNotFoundCreation();
216+
try {
217+
$envelope = $receiver->find($id);
218+
} finally {
219+
$this->phpSerializer?->enableClassNotFoundCreation(false);
220+
}
211221
if (null === $envelope) {
212222
throw new RuntimeException(sprintf('The message "%s" was not found.', $id));
213223
}
@@ -216,4 +226,14 @@ private function retrySpecificIds(string $failureTransportName, array $ids, Symf
216226
$this->runWorker($failureTransportName, $singleReceiver, $io, $shouldForce);
217227
}
218228
}
229+
230+
private function retrySpecificEnvelops(array $envelopes, string $failureTransportName, SymfonyStyle $io, bool $shouldForce)
231+
{
232+
$receiver = $this->getReceiver($failureTransportName);
233+
234+
foreach ($envelopes as $envelope) {
235+
$singleReceiver = new SingleMessageReceiver($receiver, $envelope);
236+
$this->runWorker($failureTransportName, $singleReceiver, $io, $shouldForce);
237+
}
238+
}
219239
}

src/Symfony/Component/Messenger/Command/FailedMessagesShowCommand.php

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -96,29 +96,29 @@ private function listMessages(?string $failedTransportName, SymfonyStyle $io, in
9696
$io->comment(sprintf('Displaying only \'%s\' messages', $classFilter));
9797
}
9898

99-
foreach ($envelopes as $envelope) {
100-
$currentClassName = \get_class($envelope->getMessage());
101-
102-
if ($classFilter && $classFilter !== $currentClassName) {
103-
continue;
104-
}
105-
106-
/** @var RedeliveryStamp|null $lastRedeliveryStamp */
107-
$lastRedeliveryStamp = $envelope->last(RedeliveryStamp::class);
108-
/** @var ErrorDetailsStamp|null $lastErrorDetailsStamp */
109-
$lastErrorDetailsStamp = $envelope->last(ErrorDetailsStamp::class);
110-
111-
$errorMessage = '';
112-
if (null !== $lastErrorDetailsStamp) {
113-
$errorMessage = $lastErrorDetailsStamp->getExceptionMessage();
99+
$this->phpSerializer?->enableClassNotFoundCreation();
100+
try {
101+
foreach ($envelopes as $envelope) {
102+
$currentClassName = \get_class($envelope->getMessage());
103+
104+
if ($classFilter && $classFilter !== $currentClassName) {
105+
continue;
106+
}
107+
108+
/** @var RedeliveryStamp|null $lastRedeliveryStamp */
109+
$lastRedeliveryStamp = $envelope->last(RedeliveryStamp::class);
110+
/** @var ErrorDetailsStamp|null $lastErrorDetailsStamp */
111+
$lastErrorDetailsStamp = $envelope->last(ErrorDetailsStamp::class);
112+
113+
$rows[] = [
114+
$this->getMessageId($envelope),
115+
$currentClassName,
116+
null === $lastRedeliveryStamp ? '' : $lastRedeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s'),
117+
$lastErrorDetailsStamp?->getExceptionMessage() ?? '',
118+
];
114119
}
115-
116-
$rows[] = [
117-
$this->getMessageId($envelope),
118-
$currentClassName,
119-
null === $lastRedeliveryStamp ? '' : $lastRedeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s'),
120-
$errorMessage,
121-
];
120+
} finally {
121+
$this->phpSerializer?->enableClassNotFoundCreation(false);
122122
}
123123

124124
$rowsCount = \count($rows);
@@ -148,14 +148,19 @@ private function listMessagesPerClass(?string $failedTransportName, SymfonyStyle
148148

149149
$countPerClass = [];
150150

151-
foreach ($envelopes as $envelope) {
152-
$c = \get_class($envelope->getMessage());
151+
$this->phpSerializer?->enableClassNotFoundCreation();
152+
try {
153+
foreach ($envelopes as $envelope) {
154+
$c = \get_class($envelope->getMessage());
153155

154-
if (!isset($countPerClass[$c])) {
155-
$countPerClass[$c] = [$c, 0];
156-
}
156+
if (!isset($countPerClass[$c])) {
157+
$countPerClass[$c] = [$c, 0];
158+
}
157159

158-
++$countPerClass[$c][1];
160+
++$countPerClass[$c][1];
161+
}
162+
} finally {
163+
$this->phpSerializer?->enableClassNotFoundCreation(false);
159164
}
160165

161166
if (0 === \count($countPerClass)) {
@@ -171,7 +176,12 @@ private function showMessage(?string $failedTransportName, string $id, SymfonySt
171176
{
172177
/** @var ListableReceiverInterface $receiver */
173178
$receiver = $this->getReceiver($failedTransportName);
174-
$envelope = $receiver->find($id);
179+
$this->phpSerializer?->enableClassNotFoundCreation();
180+
try {
181+
$envelope = $receiver->find($id);
182+
} finally {
183+
$this->phpSerializer?->enableClassNotFoundCreation(false);
184+
}
175185
if (null === $envelope) {
176186
throw new RuntimeException(sprintf('The message "%s" was not found.', $id));
177187
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Messenger\Stamp;
13+
14+
/**
15+
* @author Grégoire Pineau <lyrixx@lyrixx.info>
16+
*/
17+
class MessageDecodingFailedStamp implements StampInterface
18+
{
19+
}

src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class PhpSerializerTest extends TestCase
2222
{
2323
public function testEncodedIsDecodable()
2424
{
25-
$serializer = new PhpSerializer();
25+
$serializer = $this->createPhpSerializer();
2626

2727
$envelope = new Envelope(new DummyMessage('Hello'));
2828

@@ -36,7 +36,7 @@ public function testDecodingFailsWithMissingBodyKey()
3636
$this->expectException(MessageDecodingFailedException::class);
3737
$this->expectExceptionMessage('Encoded envelope should have at least a "body", or maybe you should implement your own serializer');
3838

39-
$serializer = new PhpSerializer();
39+
$serializer = $this->createPhpSerializer();
4040

4141
$serializer->decode([]);
4242
}
@@ -46,7 +46,7 @@ public function testDecodingFailsWithBadFormat()
4646
$this->expectException(MessageDecodingFailedException::class);
4747
$this->expectExceptionMessageMatches('/Could not decode/');
4848

49-
$serializer = new PhpSerializer();
49+
$serializer = $this->createPhpSerializer();
5050

5151
$serializer->decode([
5252
'body' => '{"message": "bar"}',
@@ -58,7 +58,7 @@ public function testDecodingFailsWithBadBase64Body()
5858
$this->expectException(MessageDecodingFailedException::class);
5959
$this->expectExceptionMessageMatches('/Could not decode/');
6060

61-
$serializer = new PhpSerializer();
61+
$serializer = $this->createPhpSerializer();
6262

6363
$serializer->decode([
6464
'body' => 'x',
@@ -70,7 +70,7 @@ public function testDecodingFailsWithBadClass()
7070
$this->expectException(MessageDecodingFailedException::class);
7171
$this->expectExceptionMessageMatches('/class "ReceivedSt0mp" not found/');
7272

73-
$serializer = new PhpSerializer();
73+
$serializer = $this->createPhpSerializer();
7474

7575
$serializer->decode([
7676
'body' => 'O:13:"ReceivedSt0mp":0:{}',
@@ -79,7 +79,7 @@ public function testDecodingFailsWithBadClass()
7979

8080
public function testEncodedSkipsNonEncodeableStamps()
8181
{
82-
$serializer = new PhpSerializer();
82+
$serializer = $this->createPhpSerializer();
8383

8484
$envelope = new Envelope(new DummyMessage('Hello'), [
8585
new DummyPhpSerializerNonSendableStamp(),
@@ -91,14 +91,19 @@ public function testEncodedSkipsNonEncodeableStamps()
9191

9292
public function testNonUtf8IsBase64Encoded()
9393
{
94-
$serializer = new PhpSerializer();
94+
$serializer = $this->createPhpSerializer();
9595

9696
$envelope = new Envelope(new DummyMessage("\xE9"));
9797

9898
$encoded = $serializer->encode($envelope);
9999
$this->assertTrue((bool) preg_match('//u', $encoded['body']), 'Encodes non-UTF8 payloads');
100100
$this->assertEquals($envelope, $serializer->decode($encoded));
101101
}
102+
103+
protected function createPhpSerializer(): PhpSerializer
104+
{
105+
return new PhpSerializer();
106+
}
102107
}
103108

104109
class DummyPhpSerializerNonSendableStamp implements NonSendableStampInterface

0 commit comments

Comments
 (0)
0