moleculer icon indicating copy to clipboard operation
moleculer copied to clipboard

Proposal: allow event subscriber to determine whether it is balanced

Open ngraef opened this issue 5 years ago • 4 comments

Is your feature request related to a problem? Please describe.

Letting an event publisher determine whether an event is balanced or not (emit vs broadcast) creates tightly coupled services and can cause issues among subscribers.

For example, imagine a user service publishes a user.created event. An activity service maintains a local cache of recently active users and subscribes to user.created so every instance can update its cache. An email service also subscribes to user.created because it wants a single instance to send a welcome email to the new user.

In this example, should the user service emit or broadcast the user.created event? I believe it shouldn't have to decide, because making that decision requires the publisher to know about the subscribers and the logic of their event handlers. Instead, I think each subscription should determine whether or not it needs to be balanced.

Describe the solution you'd like

I propose that a balanced: boolean property be added to the event definition to determine what kind of subscription should be created. Additionally, the emit and broadcast methods should be unified into a single method, though there are likely other ways to implement this proposal that avoid breaking changes.

// activity.service.js
module.exports = {
  name: 'activity',
  events: {
    'user.created': {
      balanced: false,
      handler(ctx) {
        // Update local user cache
      }
    }
  }
};

// email.service.js
module.exports = {
  name: 'email',
  events: {
    // Should `balanced: true` be the default?
    'user.created'(ctx) {
      // Send welcome email
    }
  }
};

Describe alternatives you've considered

Examples like the above can be solved by publishing multiple events to different groups — emit to the email group and broadcast to the activity group — to satisfy the different subscribers. However, this doesn't solve the philosophical issue that publishers and subscribers are tightly coupled.

Additional context

Inspired by research on (and possibly a solution for) #791

ngraef avatar Aug 12 '20 03:08 ngraef

Could similar functionality be achieved through naming events in a way that reflects whether they are balanced or not and then firing off both events when a user is created? If the above was implemented it would likely have to do something similar (do both a emit and broadcast for all events behind the scenes or be tightly coupled to its subscribers to know which event types it needs to send based on the subscribers configuration). Seems like it would solve for the coupling of needing to know about your subscribers when publishing an event. The downside I see to this approach is potentially performance and code-cleanliness.

Something like:

broker.emit("user.created.emit", user);
broker.broadcast("user.created.broadcast", user);

And then to subscribe:

// activity.service.js - { balanced: false }
module.exports = {
  name: 'activity',
  events: {
    'user.created.broadcast': {
      handler(ctx) {
        // Update local user cache
      }
    }
  }
};

// email.service.js - { balanced: true }
module.exports = {
  name: 'email',
  events: {
    'user.created.emit': {
      handler(ctx) {
        // Send welcome email
      }
    }
  }
};

derekaug avatar Aug 12 '20 13:08 derekaug

Thanks @ngraef, good idea, but it a very significant breaking changes (affect the protocol, as well). So it comes only soonest in 0.15. But we should elaborate it completely and cover all use-cases.

By the way, @derekaug idea is a good workaround. And you can make a middleware with decorates the broker with e sendEvent method which does the emit & broadcast calls & suffixing.

icebob avatar Aug 13 '20 17:08 icebob

As @derekaug said, the performance would likely be a problem. The workaround could work well in small implementations. For large setups, with thousands of services and even more events flying around, it can be a significant problem.

+1 for this proposal. :)

edurdias avatar Apr 27 '21 05:04 edurdias

I will start developing 0.15 soon. To implement this feature, I need concrete suggestions on how to implement it.

icebob avatar Apr 27 '21 19:04 icebob