10000 Merge branch '4.3' into 4.4 · symfony/symfony@c950130 · GitHub
[go: up one dir, main page]

Skip to content

Commit c950130

Browse files
committed
Merge branch '4.3' into 4.4
2 parents 4d8a01e + 8bf8c50 commit c950130

File tree

18 files changed

+271
-146
lines changed

18 files changed

+271
-146
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,6 +1717,7 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder
17171717
$defaultMiddleware = [
17181718
'before' => [
17191719
['id' => 'add_bus_name_stamp_middleware'],
1720+
['id' => 'reject_redelivered_message_middleware'],
17201721
['id' => 'dispatch_after_current_bus'],
17211722
['id' => 'failed_message_processing_middleware'],
17221723
],

src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
<argument type="service" id="validator" />
4949
</service>
5050

51+
<service id="messenger.middleware.reject_redelivered_message_middleware" class="Symfony\Component\Messenger\Middleware\RejectRedeliveredMessageMiddleware" />
52+
5153
<service id="messenger.middleware.failed_message_processing_middleware" class="Symfony\Component\Messenger\Middleware\FailedMessageProcessingMiddleware" />
5254

5355
<service id="messenger.middleware.traceable" class="Symfony\Component\Messenger\Middleware\TraceableMiddleware" abstract="true">

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,7 @@ public function testMessengerWithMultipleBuses()
740740
$this->assertSame([], $container->getDefinition('messenger.bus.commands')->getArgument(0));
741741
$this->assertEquals([
742742
['id' => 'add_bus_name_stamp_middleware', 'arguments' => ['messenger.bus.commands']],
743+
['id' => 'reject_redelivered_message_middleware'],
743744
['id' => 'dispatch_after_current_bus'],
744745
['id' => 'failed_message_processing_middleware'],
745746
['id' => 'send_message'],
@@ -749,6 +750,7 @@ public function testMessengerWithMultipleBuses()
749750
$this->assertSame([], $container->getDefinition('messenger.bus.events')->getArgument(0));
750751
$this->assertEquals([
751752
['id' => 'add_bus_name_stamp_middleware', 'arguments' => ['messenger.bus.events']],
753+
['id' => 'reject_redelivered_message_middleware'],
752754
['id' => 'dispatch_after_current_bus'],
753755
['id' => 'failed_message_processing_middleware'],
754756
['id' => 'with_factory', 'arguments' => ['foo', true, ['bar' => 'baz']]],

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"symfony/http-client": "^4.4|^5.0",
4646
"symfony/lock": "^4.4|^5.0",
4747
"symfony/mailer": "^4.4|^5.0",
48-
"symfony/messenger": "^4.3|^5.0",
48+
"symfony/messenger": "^4.3.6|^5.0",
4949
"symfony/mime": "^4.4|^5.0",
5050
"symfony/process": "^3.4|^4.0|^5.0",
5151
"symfony/security-csrf": "^3.4|^4.0|^5.0",
@@ -77,7 +77,7 @@
7777
"symfony/form": "<4.3",
7878
"symfony/lock": "<4.4",
7979
"symfony/mailer": "<4.4",
80-
"symfony/messenger": "<4.3",
80+
"symfony/messenger": "<4.3.6",
8181
"symfony/mime": "<4.4",
8282
"symfony/property-info": "<3.4",
8383
"symfony/security-bundle": "<4.4",

src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@
1616

1717
abstract class HttpClientTestCase extends BaseHttpClientTestCase
1818
{
19-
public function testMaxDuration()
20-
{
21-
$this->markTestSkipped('Implemented as of version 4.4');
22-
}
23-
2419
public function testAcceptHeader()
2520
{
2621
$client = $this->getHttpClient(__FUNCTION__);
@@ -80,4 +75,34 @@ public function testToStream404()
8075
$response = $client->request('GET', 'http://localhost:8057/404');
8176
$stream = $response->toStream();
8277
}
78+
79+
public function testInfoOnCanceledResponse()
80+
{
81+
$this->markTestSkipped('Implemented as of version 4.4');
82+
}
83+
84+
public function testBufferSink()
85+
{
86+
$this->markTestSkipped('Implemented as of version 4.4');
87+
}
88+
89+
public function testConditionalBuffering()
90+
{
91+
$this->markTestSkipped('Implemented as of version 4.4');
92+
}
93+
94+
public function testReentrantBufferCallback()
95+
{
96+
$this->markTestSkipped('Implemented as of version 4.4');
97+
}
98+
99+
public function testThrowingBufferCallback()
100+
{
101+
$this->markTestSkipped('Implemented as of version 4.4');
102+
}
103+
104+
public function testMaxDuration()
105+
{
106+
$this->markTestSkipped('Implemented as of version 4.4');
107+
}
83108
}

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

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,7 @@ protected function displaySingleMessage(Envelope $envelope, SymfonyStyle $io)
6161

6262
/** @var SentToFailureTransportStamp|null $sentToFailureTransportStamp */
6363
$sentToFailureTransportStamp = $envelope->last(SentToFailureTransportStamp::class);
64-
/** @var RedeliveryStamp|null $lastRedeliveryStamp */
65-
$lastRedeliveryStamp = $envelope->last(RedeliveryStamp::class);
64+
$lastRedeliveryStampWithException = $this->getLastRedeliveryStampWithException($envelope);
6665

6766
$rows = [
6867
['Class', \get_class($envelope->getMessage())],
@@ -72,13 +71,13 @@ protected function displaySingleMessage(Envelope $envelope, SymfonyStyle $io)
7271
$rows[] = ['Message Id', $id];
7372
}
7473

75-
$flattenException = null === $lastRedeliveryStamp ? null : $lastRedeliveryStamp->getFlattenException();
74+
$flattenException = null === $lastRedeliveryStampWithException ? null : $lastRedeliveryStampWithException->getFlattenException();
7675
if (null === $sentToFailureTransportStamp) {
7776
$io->warning('Message does not appear to have been sent to this transport after failing');
7877
} else {
7978
$rows = array_merge($rows, [
80-
['Failed at', null === $lastRedeliveryStamp ? '' : $lastRedeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s')],
81-
['Error', null === $lastRedeliveryStamp ? '' : $lastRedeliveryStamp->getExceptionMessage()],
79+
['Failed at', null === $lastRedeliveryStampWithException ? '' : $lastRedeliveryStampWithException->getRedeliveredAt()->format('Y-m-d H:i:s')],
80+
['Error', null === $lastRedeliveryStampWithException ? '' : $lastRedeliveryStampWithException->getExceptionMessage()],
8281
['Error Class', null === $flattenException ? '(unknown)' : $flattenException->getClass()],
8382
['Transport', $sentToFailureTransportStamp->getOriginalReceiverName()],
8483
]);
@@ -120,4 +119,16 @@ protected function getReceiver(): ReceiverInterface
120119
{
121120
return $this->receiver;
122121
}
122+
123+
protected function getLastRedeliveryStampWithException(Envelope $envelope): ?RedeliveryStamp
124+
{
125+
/** @var RedeliveryStamp $stamp */
126+
foreach (array_reverse($envelope->all(RedeliveryStamp::class)) as $stamp) {
127+
if (null !== $stamp->getExceptionMessage()) {
128+
return $stamp;
129+
}
130+
}
131+
132+
return null;
133+
}
123134
}

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
use Symfony\Component\Console\Output\ConsoleOutputInterface;
1919
use Symfony\Component\Console\Output\OutputInterface;
2020
use Symfony\Component\Console\Style\SymfonyStyle;
21-
use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
2221
use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface;
2322

2423
/**
@@ -83,14 +82,13 @@ private function listMessages(SymfonyStyle $io, int $max)
8382

8483
$rows = [];
8584
foreach ($envelopes as $envelope) {
86-
/** @var RedeliveryStamp|null $lastRedeliveryStamp */
87-
$lastRedeliveryStamp = $envelope->last(RedeliveryStamp::class);
85+
$lastRedeliveryStampWithException = $this->getLastRedeliveryStampWithException($envelope);
8886

8987
$rows[] = [
9088
$this->getMessageId($envelope),
9189
\get_class($envelope->getMessage()),
92-
null === $lastRedeliveryStamp ? '' : $lastRedeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s'),
93-
null === $lastRedeliveryStamp ? '' : $lastRedeliveryStamp->getExceptionMessage(),
90+
null === $lastRedeliveryStampWithException ? '' : $lastRedeliveryStampWithException->getRedeliveredAt()->format('Y-m-d H:i:s'),
91+
null === $lastRedeliveryStampWithException ? '' : $lastRedeliveryStampWithException->getExceptionMessage(),
9492
];
9593
}
9694

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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\Exception;
13+
14+
/**
15+
* @author Tobias Schultze <http://tobion.de>
16+
*
17+
* @experimental in 4.3
18+
*/
19+
class RejectRedeliveredMessageException extends RuntimeException
20+
{
21+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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\Middleware;
13+
14+
use Symfony\Component\Messenger\Envelope;
15+
use Symfony\Component\Messenger\Exception\RejectRedeliveredMessageException;
16+
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
17+
use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceivedStamp;
18+
19+
/**
20+
* Middleware that throws a RejectRedeliveredMessageException when a message is detected that has been redelivered by AMQP.
21+
*
22+
* The middleware runs before the HandleMessageMiddleware and prevents redelivered messages from being handled directly.
23+
* The thrown exception is caught by the worker and will trigger the retry logic according to the retry strategy.
24+
*
25+
* AMQP redelivers messages when they do not get acknowledged or rejected. This can happen when the connection times out
26+
* or an exception is thrown before acknowledging or rejecting. When such errors happen again while handling the
27+
* redelivered message, the message would get redelivered again and again. The purpose of this middleware is to prevent
28+
* infinite redelivery loops and to unblock the queue by republishing the redelivered messages as retries with a retry
29+
* limit and potential delay.
30+
*
31+
* @experimental in 4.3
32+
*
33+
* @author Tobias Schultze <http://tobion.de>
34+
*/
35+
class RejectRedeliveredMessageMiddleware implements MiddlewareInterface
36+
{
37+
public function handle(Envelope $envelope, StackInterface $stack): Envelope
38+
{
39+
// ignore the dispatched messages for retry
40+
if (null !== $envelope->last(ReceivedStamp::class)) {
41+
$amqpReceivedStamp = $envelope->last(AmqpReceivedStamp::class);
42+
43+
if ($amqpReceivedStamp instanceof AmqpReceivedStamp && $amqpReceivedStamp->getAmqpEnvelope()->isRedelivery()) {
44+
throw new RejectRedeliveredMessageException('Redelivered message from AMQP detected that will be rejected and trigger the retry logic.');
45+
}
46+
}
47+
48+
return $stack->next()->handle($envelope, $stack);
49+
}
50+
}

src/Symfony/Component/Messenger/Tests/Command/FailedMessagesRetryCommandTest.php

Lines changed: 6 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,10 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Console\Tester\CommandTester;
16-
use Symfony\Component\Debug\Exception\FlattenException as LegacyFlattenException;
17-
use Symfony\Component\ErrorRenderer\Exception\FlattenException;
1816
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
1917
use Symfony\Component\Messenger\Command\FailedMessagesRetryCommand;
2018
use Symfony\Component\Messenger\Envelope;
2119
use Symfony\Component\Messenger\MessageBusInterface;
22-
use Symfony\Component\Messenger\Retry\RetryStrategyInterface;
23-
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
24-
use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
2520
use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface;
2621

2722
class FailedMessagesRetryCommandTest extends TestCase
@@ -38,52 +33,16 @@ public function testBasicRun()
3833
// the bus should be called in the worker
3934
$bus->expects($this->exactly(2))->method('dispatch')->willReturn(new Envelope(new \stdClass()));
4035

41-
$command = new FailedMessagesRetryCommand('failure_receiver', $receiver, $bus, $dispatcher);
36+
$command = new FailedMessagesRetryCommand(
37+
'failure_receiver',
38+
$receiver,
39+
$bus,
40+
$dispatcher
41+
);
4242

4343
$tester = new CommandTester($command);
4444
$tester->execute(['id' => [10, 12]]);
4545

4646
$this->assertStringContainsString('[OK]', $tester->getDisplay());
4747
}
48-
49-
public function testExceptionOnRetry()
50-
{
51-
$receiver = $this->createMock(ListableReceiverInterface::class);
52-
$receiver->expects($this->once())->method('find')->with(10)->willReturn(new Envelope(new \stdClass()));
53-
// message will eventually be ack'ed in Worker
54-
$receiver->expects($this->once())->method('ack');
55-
56-
$dispatcher = $this->createMock(EventDispatcherInterface::class);
57-
$bus = $this->createMock(MessageBusInterface::class);
58-
// the bus should be called in the worker
59-
$bus->expects($this->at(0))
60-
->method('dispatch')
61-
->with($this->callback(function (Envelope $envelope) {
62-
$lastReceivedStamp = $envelope->last(ReceivedStamp::class);
63-
64-
return $lastReceivedStamp instanceof ReceivedStamp && \is_string($lastReceivedStamp->getTransportName());
65-
}))
66-
->will($this->throwException(new \Exception('Mock test exception')));
67-
68-
$bus->expects($this->at(1))
69-
->method('dispatch')
70-
->with($this->callback(function (Envelope $envelope) {
71-
$lastRedeliveryStamp = $envelope->last(RedeliveryStamp::class);
72-
73-
return $lastRedeliveryStamp instanceof RedeliveryStamp &&
74-
\is_string($lastRedeliveryStamp->getExceptionMessage()) &&
75-
($lastRedeliveryStamp->getFlattenException() instanceof FlattenException || $lastRedeliveryStamp->getFlattenException() instanceof LegacyFlattenException);
76-
}))
77-
->willReturn(new Envelope(new \stdClass()));
78-
79-
$retryStrategy = $this->createMock(RetryStrategyInterface::class);
80-
$retryStrategy->expects($this->once())->method('isRetryable')->with($this->isInstanceOf(Envelope::class))->willReturn(true);
81-
82-
$command = new FailedMessagesRetryCommand('failure_receiver', $receiver, $bus, $dispatcher, $retryStrategy);
83-
84-
$tester = new CommandTester($command);
85-
$tester->execute(['id' => [10]]);
86-
87-
$this->assertStringContainsString('[OK]', $tester->getDisplay());
88-
}
8948
}

0 commit comments

Comments
 (0)
0