Skip to content

[Messenger] use Envelope internally, return void, add EnvelopeHandlerInterface and other cleanups #28881

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from

Conversation

nicolas-grekas
Copy link
Member

@nicolas-grekas nicolas-grekas commented Oct 15, 2018

Q A
Branch? 4.2
Bug fix? yes
New feature? yes
BC breaks? yes
Deprecations? no
Tests pass? not yet
Fixed tickets -
License MIT
Doc PR -

Sorry in advance for this late PR, I've just reviewed the component for the first time and I think we should do some changes in its internal design, so here we are, last chance before tagging it as stable.

Each item in this list can potentially trigger a discussion. Here are the topics of this PR:

  • make everything internally deal with Envelope objects (middlewares, transports, etc.)
  • replace EnvelopeAwareInterface (for middlewares) by EnvelopeHandlerInterface (for userland handlers) [edit: bad idea, see discussion]
  • remove the return value of dispatch()+handle(): we never use it and it contradicts the very idea of async (mutable messages can be used instead, but that's not our business)
  • added string $name = null as 2nd argument to dispatch(), used as dispatching key when provided for more flexibility (it's not always possible/desirable to create a new class to define a dispatching key)
  • locating senders/handlers using the parent classes+interfaces of the message is removed. To me, locating based on the type hierarchy is a code smell that we hijack the type hierarchy to make it fit what should be done via configuration. [edit: now kept to reduce the impact of this PR - could be deprecated later if this smell is proven by experience in the future]
  • remove AllowNoHandlerMiddleware and replace it with a constructor argument on HandleMessageMiddleware: using exceptions for signaling is going to slow down the component for no real reasons to me. This solves it.
  • rename some methods / change some interfaces for consistency/ease of use

I expect this to raise some discussions. To resolve them one by one, I propose to split this PR into separate ones while we move our common understanding forward.

Meanwhile, I didn't update tests nor DI integration. I'll do as this moves forward.

*
* @author Nicolas Grekas <p@tchwork.com>
*/
interface EnvelopeHandlerInterface extends MessageHandlerInterface
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

* @return mixed
*/
public function handle($message, callable $next);
public function handle(Envelope $envelope, callable $next): void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

'message' => $message,
'class' => \get_class($message),
);
$this->logger->debug('Finished handling message {class}', $context);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/{class}/{name}

@Koc
Copy link
Contributor

Koc commented Oct 15, 2018

remove the return value of dispatch()+handle(): we never use it and it contradicts the very idea of async (mutable messages can be used instead, but that's not our business)

what about query bus? It would be nice provide query bus out of the box

@nicolas-grekas nicolas-grekas force-pushed the messenger++ branch 2 times, most recently from 59ff103 to eefb815 Compare October 16, 2018 00:26
@nicolas-grekas
Copy link
Member Author

nicolas-grekas commented Oct 16, 2018

what about query bus? It would be nice provide query bus out of the box

They could use mutable command objects (e.g. a setResult()). This would benefit the type system since the argument to this method could be type-hinted.

Right now, the return value blurs the scope of the component to me. Also look at e.g. ChainHandler: returning the array of all results makes no sense: this is configuration leaking to the outside.
Makes sense?

@ogizanagi
Copy link
Contributor

ogizanagi commented Oct 16, 2018

make everything internally deal with Envelope objects (middlewares, transports, etc.)

I didn't review this yet, but you've got my 👍 for this. I already suggested this in the past (#27322) and suggested an abstract Middleware class for those wanting only to deal with messages in their middleware.

Meanwhile, I'm not convinced EnvelopeHandlerInterface would be useful.

@nicolas-grekas
Copy link
Member Author

nicolas-grekas commented Oct 16, 2018

Meanwhile, I'm not convinced EnvelopeHandlerInterface would be useful.

Since Envelope is not an internal detail, it means ppl that use it to wrap their messages should be able to receive them also. Otherwise, why allow dispatching envelope in the first place? To me, either we make Envelope purely internal (ie never dispatch them) - or handlers need to be able to receive them, in an opt-in way.

@nicolas-grekas
Copy link
Member Author

Note that I may be missing the reason why #27322 has been rejected: right now, I'm thinking about middlewares as things that are tightly bound to Messenger so that they legitimately know about it, and about Envelope especially.
The boundary that is loosely coupled is the caller of dispatch(), and it's corresponding handlers. Those don't need to care about Envelope.
So, @sroze maybe: what are the use cases you envision where middlewares are on the outer boundary of the component?

@ogizanagi
Copy link
Contributor

ogizanagi commented Oct 16, 2018

Since Envelope is not an internal detail, [...] handlers need to be able to receive them, in an opt-in way.

It's not about the envelope being internal or not regarding this. Envelopes are meant for runtime "config" of middleware & transports. If the handler needs some data to treat the message, it should be part of it, not the envelope.

@nicolas-grekas
Copy link
Member Author

nicolas-grekas commented Oct 16, 2018

If the handler needs some data to treat the message, it should be part of it, not the envelope.

aren't there any cases where the handler will want to know about the way routing did happen? E.g. number of retries, timestamps, some routing/logging identifier, etc. - Things that could be of interest for some handlers?

@ogizanagi
Copy link
Contributor

Obviously not to me. Handlers are pure business logic. The use-cases you mention are valid as a middleware (which if really needed can mutate the message, but those are usually supposed immutable).

foreach ($this->handlers as $handler) {
$results[] = $handler($message);
$handler($envelope instanceof EnvelopeHandlerInterface ? $envelope : $envelope->getMessage());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$handler instanceof

@nicolas-grekas
Copy link
Member Author

nicolas-grekas commented Oct 17, 2018

Handlers are pure business logic. The use-cases you mention are valid as a middleware

Argument accepted, makes perfect sense. That's another argument to make middlewares deal with envelopes: they're part of the routing - use handlers for the part that is outside.

@nicolas-grekas
Copy link
Member Author

Closing here because this has been split into several PRs already - or will soon be for the remaining ideas.
See #28914, #28911, #28909, #28908, #28907

@nicolas-grekas nicolas-grekas deleted the messenger++ branch October 18, 2018 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants