feature #31471 [Messenger] Add "non sendable" stamps (weaverryan)
This PR was merged into the 4.3 branch.
Discussion
----------
[Messenger] Add "non sendable" stamps
| Q | A
| ------------- | ---
| Branch? | 4.3
| Bug fix? | yes
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #31460
| License | MIT
| Doc PR | not needed
Fixes a bug where Symfony serialization of the AmqpReceivedStamp sometimes caused problems.
It's still a mystery why the `AmqpReceivedStamp` caused a segfault *sometimes* when going through the Symfony serializer or the `VarDumper`. But, that stamp really didn't need to be sent on redelivery anyways.
I don't love making the removal the responsibility of the serializers, but it didn't work well anywhere else.
Cheers!
Commits
-------
34e7781c5c
Adding a new NonSendableStampInterface to avoid sending certain stamps
This commit is contained in:
commit
65458059d8
@ -4,6 +4,9 @@ CHANGELOG
|
||||
4.3.0
|
||||
-----
|
||||
|
||||
* Added `NonSendableStampInterface` that a stamp can implement if
|
||||
it should not be sent to a transport. Transport serializers
|
||||
must now check for these stamps and not encode them.
|
||||
* [BC BREAK] `SendersLocatorInterface` has an additional method:
|
||||
`getSenderByAlias()`.
|
||||
* Removed argument `?bool &$handle = false` from `SendersLocatorInterface::getSenders`
|
||||
|
@ -80,6 +80,22 @@ final class Envelope
|
||||
return $cloned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all stamps that implement the given type.
|
||||
*/
|
||||
public function withoutStampsOfType(string $type): self
|
||||
{
|
||||
$cloned = clone $this;
|
||||
|
||||
foreach ($cloned->stamps as $class => $stamps) {
|
||||
if ($class === $type || \is_subclass_of($class, $type)) {
|
||||
unset($cloned->stamps[$class]);
|
||||
}
|
||||
}
|
||||
|
||||
return $cloned;
|
||||
}
|
||||
|
||||
public function last(string $stampFqcn): ?StampInterface
|
||||
{
|
||||
return isset($this->stamps[$stampFqcn]) ? end($this->stamps[$stampFqcn]) : null;
|
||||
|
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Messenger\Stamp;
|
||||
|
||||
/**
|
||||
* A stamp that should not be included with the Envelope if sent to a transport.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@symfonycasts.com>
|
||||
*
|
||||
* @experimental in 4.3
|
||||
*/
|
||||
interface NonSendableStampInterface extends StampInterface
|
||||
{
|
||||
}
|
@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Messenger\Envelope;
|
||||
use Symfony\Component\Messenger\Stamp\DelayStamp;
|
||||
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
|
||||
use Symfony\Component\Messenger\Stamp\StampInterface;
|
||||
use Symfony\Component\Messenger\Stamp\ValidationStamp;
|
||||
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
|
||||
|
||||
@ -50,6 +51,30 @@ class EnvelopeTest extends TestCase
|
||||
$this->assertCount(1, $envelope->all(DelayStamp::class));
|
||||
}
|
||||
|
||||
public function testWithoutStampsOfType()
|
||||
{
|
||||
$envelope = new Envelope(new DummyMessage('dummy'), [
|
||||
new ReceivedStamp('transport1'),
|
||||
new DelayStamp(5000),
|
||||
new DummyExtendsDelayStamp(5000),
|
||||
new DummyImplementsFooBarStampInterface(),
|
||||
]);
|
||||
|
||||
$envelope2 = $envelope->withoutStampsOfType(DummyNothingImplementsMeStampInterface::class);
|
||||
$this->assertEquals($envelope, $envelope2);
|
||||
|
||||
$envelope3 = $envelope2->withoutStampsOfType(ReceivedStamp::class);
|
||||
$this->assertEmpty($envelope3->all(ReceivedStamp::class));
|
||||
|
||||
$envelope4 = $envelope3->withoutStampsOfType(DelayStamp::class);
|
||||
$this->assertEmpty($envelope4->all(DelayStamp::class));
|
||||
$this->assertEmpty($envelope4->all(DummyExtendsDelayStamp::class));
|
||||
|
||||
$envelope5 = $envelope4->withoutStampsOfType(DummyFooBarStampInterface::class);
|
||||
$this->assertEmpty($envelope5->all(DummyImplementsFooBarStampInterface::class));
|
||||
$this->assertEmpty($envelope5->all());
|
||||
}
|
||||
|
||||
public function testLast()
|
||||
{
|
||||
$receivedStamp = new ReceivedStamp('transport');
|
||||
@ -92,3 +117,16 @@ class EnvelopeTest extends TestCase
|
||||
$this->assertCount(1, $envelope->all(ReceivedStamp::class));
|
||||
}
|
||||
}
|
||||
|
||||
class DummyExtendsDelayStamp extends DelayStamp
|
||||
{
|
||||
}
|
||||
interface DummyFooBarStampInterface extends StampInterface
|
||||
{
|
||||
}
|
||||
interface DummyNothingImplementsMeStampInterface extends StampInterface
|
||||
{
|
||||
}
|
||||
class DummyImplementsFooBarStampInterface implements DummyFooBarStampInterface
|
||||
{
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\Messenger\Tests\Transport\Serialization;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Messenger\Envelope;
|
||||
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
|
||||
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
|
||||
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
|
||||
use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer;
|
||||
|
||||
@ -63,4 +64,20 @@ class PhpSerializerTest extends TestCase
|
||||
'body' => 'O:13:"ReceivedSt0mp":0:{}',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testEncodedSkipsNonEncodeableStamps()
|
||||
{
|
||||
$serializer = new PhpSerializer();
|
||||
|
||||
$envelope = new Envelope(new DummyMessage('Hello'), [
|
||||
new DummyPhpSerializerNonSendableStamp(),
|
||||
]);
|
||||
|
||||
$encoded = $serializer->encode($envelope);
|
||||
$this->assertNotContains('DummyPhpSerializerNonSendableStamp', $encoded['body']);
|
||||
}
|
||||
}
|
||||
|
||||
class DummyPhpSerializerNonSendableStamp implements NonSendableStampInterface
|
||||
{
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\Messenger\Tests\Transport\Serialization;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Messenger\Envelope;
|
||||
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
|
||||
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
|
||||
use Symfony\Component\Messenger\Stamp\SerializerStamp;
|
||||
use Symfony\Component\Messenger\Stamp\ValidationStamp;
|
||||
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
|
||||
@ -193,4 +194,19 @@ class SerializerTest extends TestCase
|
||||
'headers' => ['type' => 'NonExistentClass'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function testEncodedSkipsNonEncodeableStamps()
|
||||
{
|
||||
$serializer = new Serializer();
|
||||
|
||||
$envelope = new Envelope(new DummyMessage('Hello'), [
|
||||
new DummySymfonySerializerNonSendableStamp(),
|
||||
]);
|
||||
|
||||
$encoded = $serializer->encode($envelope);
|
||||
$this->assertNotContains('DummySymfonySerializerNonSendableStamp', print_r($encoded['headers'], true));
|
||||
}
|
||||
}
|
||||
class DummySymfonySerializerNonSendableStamp implements NonSendableStampInterface
|
||||
{
|
||||
}
|
||||
|
@ -11,14 +11,14 @@
|
||||
|
||||
namespace Symfony\Component\Messenger\Transport\AmqpExt;
|
||||
|
||||
use Symfony\Component\Messenger\Stamp\StampInterface;
|
||||
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
|
||||
|
||||
/**
|
||||
* Stamp applied when a message is received from Amqp.
|
||||
*
|
||||
* @experimental in 4.3
|
||||
*/
|
||||
class AmqpReceivedStamp implements StampInterface
|
||||
class AmqpReceivedStamp implements NonSendableStampInterface
|
||||
{
|
||||
private $amqpEnvelope;
|
||||
private $queueName;
|
||||
|
@ -11,14 +11,14 @@
|
||||
|
||||
namespace Symfony\Component\Messenger\Transport\Doctrine;
|
||||
|
||||
use Symfony\Component\Messenger\Stamp\StampInterface;
|
||||
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
|
||||
|
||||
/**
|
||||
* @author Vincent Touzet <vincent.touzet@gmail.com>
|
||||
*
|
||||
* @experimental in 4.3
|
||||
*/
|
||||
class DoctrineReceivedStamp implements StampInterface
|
||||
class DoctrineReceivedStamp implements NonSendableStampInterface
|
||||
{
|
||||
private $id;
|
||||
|
||||
|
@ -11,14 +11,14 @@
|
||||
|
||||
namespace Symfony\Component\Messenger\Transport\RedisExt;
|
||||
|
||||
use Symfony\Component\Messenger\Stamp\StampInterface;
|
||||
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
|
||||
|
||||
/**
|
||||
* @author Alexander Schranz <alexander@sulu.io>
|
||||
*
|
||||
* @experimental in 4.3
|
||||
*/
|
||||
class RedisReceivedStamp implements StampInterface
|
||||
class RedisReceivedStamp implements NonSendableStampInterface
|
||||
{
|
||||
private $id;
|
||||
|
||||
|
@ -13,6 +13,7 @@ namespace Symfony\Component\Messenger\Transport\Serialization;
|
||||
|
||||
use Symfony\Component\Messenger\Envelope;
|
||||
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
|
||||
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
|
||||
|
||||
/**
|
||||
* @author Ryan Weaver<ryan@symfonycasts.com>
|
||||
@ -40,6 +41,8 @@ class PhpSerializer implements SerializerInterface
|
||||
*/
|
||||
public function encode(Envelope $envelope): array
|
||||
{
|
||||
$envelope = $envelope->withoutStampsOfType(NonSendableStampInterface::class);
|
||||
|
||||
$body = addslashes(serialize($envelope));
|
||||
|
||||
return [
|
||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\Messenger\Transport\Serialization;
|
||||
use Symfony\Component\Messenger\Envelope;
|
||||
use Symfony\Component\Messenger\Exception\LogicException;
|
||||
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
|
||||
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
|
||||
use Symfony\Component\Messenger\Stamp\SerializerStamp;
|
||||
use Symfony\Component\Messenger\Stamp\StampInterface;
|
||||
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
||||
@ -98,6 +99,8 @@ class Serializer implements SerializerInterface
|
||||
$context = $serializerStamp->getContext() + $context;
|
||||
}
|
||||
|
||||
$envelope = $envelope->withoutStampsOfType(NonSendableStampInterface::class);
|
||||
|
||||
$headers = ['type' => \get_class($envelope->getMessage())] + $this->encodeStamps($envelope);
|
||||
|
||||
return [
|
||||
|
@ -39,6 +39,9 @@ interface SerializerInterface
|
||||
* Encodes an envelope content (message & stamps) to a common format understandable by transports.
|
||||
* The encoded array should only contain scalars and arrays.
|
||||
*
|
||||
* Stamps that implement NonSendableStampInterface should
|
||||
* not be encoded.
|
||||
*
|
||||
* The most common keys of the encoded array are:
|
||||
* - `body` (string) - the message body
|
||||
* - `headers` (string<string>) - a key/value pair of headers
|
||||
|
Reference in New Issue
Block a user