symfony: [Messenger] doesn't recognize issues in handler when it's a generator

Symfony version(s) affected

6.4.0

Description

When the handler is a generator (which you might want if using it sync, and shouldn’t be an issue when using async, the values just get ignored), Messenger doesn’t recognize failures to execute the handler.

How to reproduce

Do this

#[AsHandler]
class MessageHandler {
     function __invoke(Message $message): iterable
    {
        dd($message);
        yield $message;
    }
}

From my experimentations, this works as expected when using sync transport, but fails with async (in my case Redis), it doesn’t recognize the handler having failed.

Possible Solution

Check for the handler being a generator?

Additional Context

No response

About this issue

  • Original URL
  • State: open
  • Created 5 months ago
  • Comments: 48 (46 by maintainers)

Most upvoted comments

this should have been a hint nothing would consume it async

That’s what I’m saying, I didn’t consider me logging out the progress is actually doing the processing

(I’m not 100% sure I follow the discussion, please forgive me if I make wrong assumptions and ignore the rest of the message if that is the case)

If I’m understanding it correctly, I don’t see why message handlers are special and would need special handling (using runtime checks) compared to any other callable argument in the Symfony ecosystem. Wouldn’t this be the case for all callables anywhere in the Symfony code? (e.g. event listeners)

To me, that proves that this is not a Messenger bug (nor feature), but rather part of the PHP language (and even because being lazy is the goal of the Generator PHP feature).


Maybe the thing we can research is why sync transport works. I think people are using the sync transport when developing locally, it would be useful if we can reveal the wrong usage of generators when developing locally.

@cizordj many projects don’t use the sync mode at all. Those projects could easily enable a rule ensure that all callables tagged as AsMessageHandler don’t return anything. Of course, if your project relies on both modes, things get harder.

It’s a feature IMHO. But I dont see the purpose of it, but maybe I’m missing it.

the handler is not a generator. it returns a generator.

I think the reason this won’t work is because the code inside this function will not be called until the returned Generator is rewound. So if the return value is ignored, your code simply does not run (because your code is actually part of the iterator being returned and ignored).

To me, the bug is that you should not use a generator in a place that does not expect returning an iterator that will be consumed (or a place expecting to trigger an exception synchronously and not later in the returned iterator for that matter)