Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bug #34107 [Messenger] prevent infinite redelivery loops and blocked …
…queues (Tobion) This PR was merged into the 4.3 branch. Discussion ---------- [Messenger] prevent infinite redelivery loops and blocked queues | Q | A | ------------- | --- | Branch? | 4.3 | Bug fix? | yes | New feature? | no <!-- please update src/**/CHANGELOG.md files --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tickets | Fix #32055 | License | MIT | Doc PR | This PR solves a very common fitfall of amqp redeliveries. It's for example explained in https://blog.forma-pro.com/rabbitmq-redelivery-pitfalls-440e0347f4e0 Newer RabbitMQ versions provide a solution for this by itself but only for quorum queues and not the classic ones, see rabbitmq/rabbitmq-server#1889 This PR adds a middleware that throws a RejectRedeliveredMessageException when a message is detected that has been redelivered by AMQP. The middleware runs before the HandleMessageMiddleware and prevents redelivered messages from being handled directly. The thrown exception is caught by the worker and will trigger the retry logic according to the retry strategy. AMQP redelivers messages when they do not get acknowledged or rejected. This can happen when the connection times out or an exception is thrown before acknowledging or rejecting. When such errors happen again while handling the redelivered message, the message would get redelivered again and again. The purpose of this middleware is to prevent infinite redelivery loops and to unblock the queue by republishing the redelivered messages as retries with a retry limit and potential delay. Commits ------- d211904 [Messenger] prevent infinite redelivery loops and blocked queues
- Loading branch information
Showing
8 changed files
with
91 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
src/Symfony/Component/Messenger/Exception/RejectRedeliveredMessageException.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?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\Exception; | ||
|
||
/** | ||
* @author Tobias Schultze <http://tobion.de> | ||
* | ||
* @experimental in 4.3 | ||
*/ | ||
class RejectRedeliveredMessageException extends RuntimeException | ||
{ | ||
} |
50 changes: 50 additions & 0 deletions
50
src/Symfony/Component/Messenger/Middleware/RejectRedeliveredMessageMiddleware.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<?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\Middleware; | ||
|
||
use Symfony\Component\Messenger\Envelope; | ||
use Symfony\Component\Messenger\Exception\RejectRedeliveredMessageException; | ||
use Symfony\Component\Messenger\Stamp\ReceivedStamp; | ||
use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceivedStamp; | ||
|
||
/** | ||
* Middleware that throws a RejectRedeliveredMessageException when a message is detected that has been redelivered by AMQP. | ||
* | ||
* The middleware runs before the HandleMessageMiddleware and prevents redelivered messages from being handled directly. | ||
* The thrown exception is caught by the worker and will trigger the retry logic according to the retry strategy. | ||
* | ||
* AMQP redelivers messages when they do not get acknowledged or rejected. This can happen when the connection times out | ||
* or an exception is thrown before acknowledging or rejecting. When such errors happen again while handling the | ||
* redelivered message, the message would get redelivered again and again. The purpose of this middleware is to prevent | ||
* infinite redelivery loops and to unblock the queue by republishing the redelivered messages as retries with a retry | ||
* limit and potential delay. | ||
* | ||
* @experimental in 4.3 | ||
* | ||
* @author Tobias Schultze <http://tobion.de> | ||
*/ | ||
class RejectRedeliveredMessageMiddleware implements MiddlewareInterface | ||
{ | ||
public function handle(Envelope $envelope, StackInterface $stack): Envelope | ||
{ | ||
// ignore the dispatched messages for retry | ||
if (null !== $envelope->last(ReceivedStamp::class)) { | ||
$amqpReceivedStamp = $envelope->last(AmqpReceivedStamp::class); | ||
|
||
if ($amqpReceivedStamp instanceof AmqpReceivedStamp && $amqpReceivedStamp->getAmqpEnvelope()->isRedelivery()) { | ||
throw new RejectRedeliveredMessageException('Redelivered message from AMQP detected that will be rejected and trigger the retry logic.'); | ||
} | ||
} | ||
|
||
return $stack->next()->handle($envelope, $stack); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters