8000 [Doctrine][Messenger] Prevents multiple TransportMessageIdStamp being… · symfony/symfony@f44c5f4 · GitHub
[go: up one dir, main page]

Skip to content

Commit f44c5f4

Browse files
committed
[Doctrine][Messenger] Prevents multiple TransportMessageIdStamp being stored in envelope
- Multiple TransportMessageIdStamps can heavily increase message size on multiple retries, to prevent that when message is fetched existing TransportMessageIdStamps are discarded before new one is added. - Replaces static calls to \PHPUnit\Framework\TestCase::expectException in DoctrineReceiverTest test with instance calls. Fixes: #49637
1 parent 6ba6441 commit f44c5f4

File tree

3 files changed

+88
-16
lines changed

3 files changed

+88
-16
lines changed

CHANGELOG-6.4.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ in 6.4 minor versions.
77
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
88
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v6.4.0...v6.4.1
99

10+
* 6.4.18 (2025-xx-xx)
11+
12+
* bug #49637 [Doctrine][Messenger] Prevents multiple `TransportMessageIdStamp` being stored in envelope (rtreffler)
13+
1014
* 6.4.17 (2024-12-31)
1115

1216
* bug #59304 [PropertyInfo] Remove ``@internal`` from `PropertyReadInfo` and `PropertyWriteInfo` (Dario Guarracino)
@@ -29,7 +33,7 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c
2933
* 6.4.16 (2024-11-27)
3034

3135
* bug #59013 [HttpClient] Fix checking for private IPs before connecting (nicolas-grekas)
32-
* bug #58562 [HttpClient] Close gracefull when the server closes the connection abruptly (discordier)
36+
* bug #58562 [HttpClient] Close gracefully when the server closes the connection abruptly (discordier)
3337
* bug #59007 [Dotenv] read runtime config from composer.json in debug dotenv command (xabbuh)
3438
* bug #58963 [PropertyInfo] Fix write visibility for Asymmetric Visibility and Virtual Properties (xabbuh, pan93412)
3539
* bug #58983 [Translation] [Bridge][Lokalise] Fix empty keys array in PUT, DELETE requests causing Lokalise API error (DominicLuidold)
@@ -328,7 +332,7 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c
328332
* bug #54105 [Messenger] Improve deadlock handling on `ack()` and `reject()` (jwage)
329333
* bug #54242 [HttpClient] [EventSourceHttpClient] Fix consuming SSEs with \r\n separator (fancyweb)
330334
* bug #54487 [Validator] Accept `Stringable` in `ExecutionContext::build/addViolation()` (alexandre-daubois)
331-
* bug #54456 [DomCrawler] Encode html entities only if nessecary (ausi)
335+
* bug #54456 [DomCrawler] Encode html entities only if necessary (ausi)
332336
* bug #54484 [Serializer] reset backed_enum priority, and re-prioritise translatable (GwendolenLynch)
333337
* bug #54471 [Filesystem] Strengthen the check of file permissions in `dumpFile` (alexandre-daubois)
334338
* bug #54403 [FrameworkBundle] [Command] Fix #54402: Suppress PHP warning when is_readable() tries to access dirs outside of open_basedir restrictions (Jeldrik Geraedts)
@@ -358,7 +362,7 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c
358362
* bug #54191 [Validator] add missing invalid extension error entry (xabbuh)
359363
* bug #54194 [PropertyAccess] Fix checking for missing properties (nicolas-grekas)
360364
* bug #54201 [Lock] Check the correct SQLSTATE error code for MySQL (edomato)
361-
* bug #54252 [Lock] compatiblity with redis cluster 7 (bastnic)
365+
* bug #54252 [Lock] compatibility with redis cluster 7 (bastnic)
362366
* bug #54124 [Messenger] trigger retry logic when message is a redelivery (nikophil)
363367
* bug #54254 [HttpKernel] Fix creating `ReflectionMethod` with only one argument (alexandre-daubois)
364368
* bug #54219 [Validator] Allow BICs’ first four characters to be digits (MatTheCat)
@@ -894,4 +898,3 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c
894898
* feature #43 Create PSR-7 messages using PSR-17 factories (ajgarlag)
895899
* feature #45 Fixed broken build (Nyholm)
896900
* feature #1 Initial support (dunglas)
897-

src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineReceiverTest.php

Lines changed: 75 additions & 8 deletions
55F
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
use Symfony\Component\Messenger\Transport\Serialization\Serializer;
2929
use Symfony\Component\Serializer as SerializerComponent;
3030
use Symfony\Component\Serializer\Encoder\JsonEncoder;
31+
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
32+
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
3133
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
3234

3335
class DoctrineReceiverTest extends TestCase
@@ -100,6 +102,23 @@ public function testOccursRetryableExceptionFromConnection()
100102
$receiver->get();
101103
}
102104

105+
public function testGetReplacesExistingTransportMessageIdStamps()
106+
{
107+
$serializer = $this->createSerializer();
108+
109+
$doctrineEnvelope = $this->createRetriedDoctrineEnvelope();
110+
$connection = $this->createMock(Connection::class);
111+
$connection->method('get')->willReturn($doctrineEnvelope);
112+
113+
$receiver = new DoctrineReceiver($connection, $serializer);
114+
$actualEnvelopes = $receiver->get();
115+
/** @var Envelope $actualEnvelope */
116+
$actualEnvelope = $actualEnvelopes[0];
117+
$messageIdStamps = $actualEnvelope->all(TransportMessageIdStamp::class);
118+
119+
$this->assertCount(1, $messageIdStamps);
120+
}
121+
103122
public function testAll()
104123
{
105124
$serializer = $this->createSerializer();
@@ -115,6 +134,24 @@ public function testAll()
115134
$this->assertEquals(new DummyMessage('Hi'), $actualEnvelopes[0]->getMessage());
116135
}
117136

137+
public function testAllReplacesExistingTransportMessageIdStamps()
138+
{
139+
$serializer = $this->createSerializer();
140+
141+
$doctrineEnvelope1 = $this->createRetriedDoctrineEnvelope();
142+
$doctrineEnvelope2 = $this->createRetriedDoctrineEnvelope();
143+
$connection = $this->createMock(Connection::class);
144+
$connection->method('findAll')->willReturn([$doctrineEnvelope1, $doctrineEnvelope2]);
145+
146+
$receiver = new DoctrineReceiver($connection, $serializer);
147+
$actualEnvelopes = $receiver->all();
148+
foreach ($actualEnvelopes as $actualEnvelope) {
149+
$messageIdStamps = $actualEnvelope->all(TransportMessageIdStamp::class);
150+
151+
$this->assertCount(1, $messageIdStamps);
152+
}
153+
}
154+
118155
public function testFind()
119156
{
120157
$serializer = $this->createSerializer();
@@ -128,6 +165,21 @@ public function testFind()
128165
$this->assertEquals(new DummyMessage('Hi'), $actualEnvelope->getMessage());
129166
}
130167

168+
public function testFindReplacesExistingTransportMessageIdStamps()
169+
{
170+
$serializer = $this->createSerializer();
171+
172+
$doctrineEnvelope = $this->createRetriedDoctrineEnvelope();
173+
$connection = $this->createMock(Connection::class);
174+
$connection->method('find')->with(3)->willReturn($doctrineEnvelope);
175+
176+
$receiver = new DoctrineReceiver($connection, $serializer);
177+
$actualEnvelope = $receiver->find(3);
178+
$messageIdStamps = $actualEnvelope->all(TransportMessageIdStamp::class);
179+
180+
$this->assertCount(1, $messageIdStamps);
181+
}
182+
131183
public function testAck()
132184
{
133185
$serializer = $this->createSerializer();
@@ -195,7 +247,7 @@ public function testAckThrowsRetryableExceptionAndRetriesFail()
195247
->with('1')
196248
->willThrowException($deadlockException);
197249

198-
self::expectException(TransportException::class);
250+
$this->expectException(TransportException::class);
199251
$receiver->ack($envelope);
200252
}
201253

@@ -215,7 +267,7 @@ public function testAckThrowsException()
215267
->with('1')
216268
->willThrowException($exception);
217269

218-
self::expectException($exception::class);
270+
$this->expectException($exception::class);
219271
$receiver->ack($envelope);
220272
}
221273

@@ -286,7 +338,7 @@ public function testRejectThrowsRetryableExceptionAndRetriesFail()
286338
->with('1')
287339
->willThrowException($deadlockException);
288340

289-
self::expectException(TransportException::class);
341+
$this->expectException(TransportException::class);
290342
$receiver->reject($envelope);
291343
}
292344

@@ -306,7 +358,7 @@ public function testRejectThrowsException()
306358
->with('1')
307359
->willThrowException($exception);
308360

309-
self::expectException($exception::class);
361+
$this->expectException($exception::class);
310362
$receiver->reject($envelope);
311363
}
312364

@@ -321,12 +373,27 @@ private function createDoctrineEnvelope(): array
321373
];
322374
}
323375

376+
private function createRetriedDoctrineEnvelope(): array
377+
{
378+
return [
379+
'id' => 3,
380+
'body' => '{"message": "Hi"}',
381+
'headers' => [
382+
'type' => DummyMessage::class,
383+
'X-Message-Stamp-Symfony\Component\Messenger\Stamp\BusNameStamp' => '[{"busName":"messenger.bus.default"}]',
384+
'X-Message-Stamp-Symfony\Component\Messenger\Stamp\TransportMessageIdStamp' => '[{"id":1},{"id":2}]',
385+
'X-Message-Stamp-Symfony\Component\Messenger\Stamp\ErrorDetailsStamp' => '[{"exceptionClass":"Symfony\\\\Component\\\\Messenger\\\\Exception\\\\RecoverableMessageHandlingException","exceptionCode":0,"exceptionMessage":"","flattenException":null}]',
386+
'X-Message-Stamp-Symfony\Component\Messenger\Stamp\DelayStamp' => '[{"delay":1000},{"delay":1000}]',
387+
'X-Message-Stamp-Symfony\Component\Messenger\Stamp\RedeliveryStamp' => '[{"retryCount":1,"redeliveredAt":"2025-01-05T13:58:25+00:00"},{"retryCount":2,"redeliveredAt":"2025-01-05T13:59:26+00:00"}]',
388+
'Content-Type' => 'application/json',
389+
],
390+
];
391+
}
392+
324393
private function createSerializer(): Serializer
325394
{
326-
$serializer = new Serializer(
327-
new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()])
395+
return new Serializer(
396+
new SerializerComponent\Serializer([new DateTimeNormalizer(), new ArrayDenormalizer(), new ObjectNormalizer()], ['json' => new JsonEncoder()])
328397
);
329-
330-
return $serializer;
331398
}
332399
}

src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/DoctrineReceiver.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,12 @@ private function createEnvelopeFromData(array $data): Envelope
141141
throw $exception;
142142
}
143143

144-
return $envelope->with(
145-
new DoctrineReceivedStamp($data['id']),
146-
new TransportMessageIdStamp($data['id'])
147-
);
144+
r 70C1 eturn $envelope
145+
->withoutAll(TransportMessageIdStamp::class)
146+
->with(
147+
new DoctrineReceivedStamp($data['id']),
148+
new TransportMessageIdStamp($data['id'])
149+
);
148150
}
149151

150152
private function withRetryableExceptionRetry(callable $callable): void

0 commit comments

Comments
 (0)
0