3

I'm using Symfony Messenger and I want to keep dispatching a message in the handler until it has been dispatched a number of times.

How can I keep track of that?

This is the code of my handler class so far:

class RetryTestHandler implements MessageHandlerInterface
{
    /**
    * @var EntityManagerInterface
    */
    private $entityManager;
    /**
     * @var MessageBusInterface
     */
    private $bus;

    public function __construct(MessageBusInterface $bus, EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
        $this->bus = $bus;
    }

    public function __invoke(RetryTest $message)
    {
        // TODO: Keep dispatching message until it has been dispatched 10 times?
        $this->bus->dispatch(new RetryTest("This is a test!"), [
            new DelayStamp(5000)
        ]);
    }
}

yivi
  • 42,438
  • 18
  • 116
  • 138
johnny
  • 135
  • 2
  • 4
  • 12

1 Answers1

5

To add metadata to your messages, you can use stamps.

Which you can later use in your own custom middleware.

E.g. for this custom StampInterface implementing class:

class LoopCount implements StampInterface {


    private int $count; 

    public function __construct($count) {
        $this->count = $count;
    }

    public function getCount(): int {
        return $this->count;
    } 
}

Then create your own middleware that checks for this stamp and re-dispatches after handling:

class ResendingMiddleware implements MiddlewareInterface
{
     private $bus;

     public function __construct(MessageBusInterface $bus) {
           $this->bus = $bus;
    }

    public function handle(Envelope $envelope, StackInterface $stack): Envelope
    {

        $envelope = $stack->next()->handle($envelope, $stack);

        if (null !== $stamp = $envelope->last(LoopCount::class)) {
            $count = $stamp->getCount();
        } else {
            return $envelope;
        }

        // Stop dispatching
        if ($count > 9) {
            return $envelope;
        }

        $this->bus->dispatch(new RetryTest("Dit is een test"), [
            new DelayStamp(5000),
            new LoopCount($count + 1)
        ]);

        return $envelope;
    }

If it was processed more than 9 times, consume the message without doing anything.

You need also to add the middleware to the configuration:

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

I wrote this in a hurry and can't test it right now, but the base should help you go in the right direction. Test and debug, and you'll get it working. I'll get back to this later to try to see if there is anything missing

johnny
  • 135
  • 2
  • 4
  • 12
yivi
  • 42,438
  • 18
  • 116
  • 138
  • Thanks for the help but I'm getting a HandlerException -> call to undefined method last(). I'm assuming I need to use an Envelope since the last() method belongs to an Envelope? – johnny Apr 07 '20 at 12:38
  • But do you know what's causing the error? is it because I don't have the message as the parameter of the __invoke method? – johnny Apr 07 '20 at 13:20
  • Ok, wrote a quick middleware for this. It's not fully tested, sorry; troubles at work and I need to get back to that. But you should be able to use the above to finish the project. If you find bugs, do not hesitate in suggesting edits. – yivi Apr 07 '20 at 14:02
  • So in the middleware handle() method I only need to return the envelope when the count is more than 9? But the return type is Envelope so I'm getting an error: Return value of handle() must be an instance of Envelope, none returned because I'm only returning the envelope in the if statement (more than 9 check). – johnny Apr 08 '20 at 09:26
  • I forgot to add the return statement at the end. As I said, I wrote it in a hurry and didn't test it. But between this and the docs you should be able to finish the implementation. Maybe this afternoon I'll be able to run it properly and test it. – yivi Apr 08 '20 at 09:34
  • Let me know if you get it working, and if there is anything else you found in the answer that need fixing. – yivi Apr 08 '20 at 09:37
  • Does this work? I tried this without success. Did someone got this working? – Alfonso Fernandez-Ocampo Dec 09 '22 at 15:22