kuzzleio / kuzzle

Open-source Back-end, self-hostable & ready to use - Real-time, storage, advanced search - Web, Apps, Mobile, IoT -
https://kuzzle.io
Apache License 2.0
1.43k stars 123 forks source link

Trigger event from plugin #420

Closed farwayer closed 7 years ago

farwayer commented 7 years ago

I want to throw error during plugin initialization with log:error event. But look like plugin must be privileged to get access to pluginManager. I do not need access to any internal functionality nor any internal data. Only throw event.

I think throwing events it's very useful functionality for plugins and it should be available to all modules. Some plugins may throw events and another may catch them. It's very valuable case. I propose to add trigger() method to plugin context.

Also it will be nice to have logger helper object inside context with warn(), info(), debug(), verbose() and error() methods. This functions should throw log:* events. For convenience only.

xbill82 commented 7 years ago

Hi @farwayer sorry for the late reply. As you can see, plugins will be soon able to send messages to the logger, which is a very important need that you pointed out, and we thank you for that. On the other side, we are thinking about exposing the trigger() method, so that plugins may trigger events on their own (even custom events, in this case). We didn't take the time to thoroughly talk about this feature with all the team but we'll do it soon (but we won't implement this feature in a rush since it may have consequences on the whole plugin architecture).

Again, thanks for your contributions and stay tuned!

xbill82 commented 7 years ago

My personal thoughts on this subject involve the use in Kuzzle of a Mailer plugin within a shopping cart checkout process. Imagine that

What would be the best way to do it?

Any thoughts are welcome.

farwayer commented 7 years ago

Thank you guys for your attention! Event system has more power. Let's discuss your example.

Think a bit what is really want to do Checkout controller. Does he want send email? No at all. Actually Checkout controller should notify user about purchase status. From this point of view things become more interesting.

We have decided to notify user by email. So lets add EmailUserNotificator. Plugin will catch notify-user events and send emails to user. Over time we think that emails is obsolete (I don't think so :smiley:) and we certainly should add SMS notifications (or WhatsApp or Slack or whatever). In your situation you will need to modify Checkout controller. In system based on events it will only need to add new SMSUserNotificator plugin. Thats all. And even more: at any time you can turn on/off certain notification type without code change.

Another good example is logger. Different loggers can write events to file, send over network, notify about critical errors by Slack.

But there is le revers de la médaille. First of all there is harder to debug event systems. Especially if events dispatched async and stacktrace missed. Second is you can forget to add some important plugins and it will be silently ignored. Solution in this case is create dependency system with required and optional features provided by another plugins. It will be usefull in any case regardless of using or not event system. It is not for kuzzle 1.0 of course.

xbill82 commented 7 years ago

:thinking:

I wouldn't say that event systems are absolutely more powerful. They just embrace a different approach. In event systems, entities are responsible of notifiying other entities (they know nothing about) with chunks of their state. Listeners are responsible to listening these events and act consequently. Take the Checkout example

More generally: given an action, in the event-based approach, the listeners are responsible of performing the action, while in the imperative approach the caller (i.e. the emitter) is responsible of performing the action.

I'm not really a promoter of imperative approaches and, yes, event-based approaches use to look neat in terms of concern separation and component decoupling. We are legitimate to say that, here, the Checkout plugin is kept reusable, which is true. But what about the UserNotifier? Even if it's living in the eventful world, it is actually coupled to the checkout plugin. And that is for the following reasons

My point is that, in your example, one of the two components is not generic, so maybe the logic does not need to be split. Notifying the user is a concern of the Checkout plugin. What the Checkout plugin should not be responsible of is the way these notifications are sent.

A more reusable plugin would be, IMHO, a generic MailNotification (or SMS or Whatsapp or Slack) plugin, which would just enable the communication with a third-party service. Such a plugin shouldn't be responsible of listening to events, since it's meant to be a generic plugin.

To sum-up, IMHO, the main goal of the Kuzzle Controller Plugins is to extend the Kuzzle API with new methods to call. And this is bound by design to the existence of the frontend (which communicates with the backend in an imperative way, i.e. by calling methods). Making the cross-plugin communication imperative keeps this mechanism consistent without introducing a new, different, one.

It is still kind of difficult to clearly express the reasons why I feel that the event system is not necessary (and even a not-so-good idea), so this is a draft of my views.

Again, thanks a lot for your discussion, it really helps us pushing things forward!

dbengsch commented 7 years ago

@farwayer The PR #557 should solve part of your issue about handling logs, this feature should be available in the next release (1.0.0-RC8)

farwayer commented 7 years ago

@dbengsch Thank you for notification! I saw it already. Good job!

@xbill82 I had in mind a slightly different thing. It is not about plugin event generation when something happened.

I meant service system when some plugins can provide functionality to others but without tight coupling. For example EmailUserNotificator and SMSUserNotificator can subscribe to notify-user event and send messages to user when some controller request it. On the another side CheckoutController don't know who is engaged in this work. So we have a very flexible system. You can very simple replace one plugin with another in runtime without changing code.

Of course events system is only one of possible implementation. Maybe it will be better to implement separate provider service registry controlled by the kuzzle core. Just like dynamic context.accessors. CheckoutController can say to core: I need something that can notify user. And will receive one or several providers.