0

If consuming message fails message is re-queued with a delay by default. Is there a way to add a counter to a message so I could know if message is on its last attempt?

This is desired behavior:

First attempt:

App\Message\Message {
  body: array:2 [
    "id" => 2
    "alias" => "some_alias",
    "attempt" => 0,
  ]
}

First retry:

App\Message\Message {
  body: array:2 [
    "id" => 2
    "alias" => "some_alias",
    "attempt" => 1,
  ]
}

Second retry:

App\Message\Message {
  body: array:2 [
    "id" => 2
    "alias" => "some_alias",
    "attempt" => 2,
  ]
}

Third retry:

App\Message\Message {
  body: array:2 [
    "id" => 2
    "alias" => "some_alias",
    "attempt" => 3,
  ]
}
PlaviZG
  • 79
  • 1
  • 7

1 Answers1

3

Solution

messenger.yaml:

...
buses:
            messenger.bus.default:
                middleware:
    # service ids that implement Symfony\Component\Messenger\Middleware
                    - 'App\Middleware\RetryMiddleware'
...

App\Middleware\RetryMiddleware:

namespace App\MessageMiddleware;

use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Middleware\StackInterface;
use Psr\Log\LoggerInterface;

class RetryMiddleware implements MiddlewareInterface
{
    public function handle(Envelope $envelope, StackInterface $stack): Envelope
    {
        try {
            return $stack->next()->handle($envelope, $stack);
        } catch (\Throwable $error) {
            $msg = $envelope->getMessage();
            $body = $msg->getBody();
            $body['attempt']++;
            $msg->setBody($body);

            //rethrow same error
            throw $error;
        }
    }
}

App\Message:

namespace App\Message;


class  Message
{
    public $body;

    public function getBody()
    {
        return $this->body;
    }

    public function setBody(array $body): void
    {
        $this->body = $body;
    }
}
Fabien Sa
  • 9,135
  • 4
  • 37
  • 44
PlaviZG
  • 79
  • 1
  • 7