Skip to content
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

Remove the need for pins #58

Open
nfantone opened this issue Oct 13, 2016 · 6 comments
Open

Remove the need for pins #58

nfantone opened this issue Oct 13, 2016 · 6 comments

Comments

@nfantone
Copy link
Collaborator

nfantone commented Oct 13, 2016

@rjrodger and @mcdonnelldean I've been looking for a way to avoid the need for users to set pins on clients and/or listeners (I believe your plans include deprecating them in a not-so-distant future?). Currently, they don't really serve much purpose other than feeding the exported transport/utils functions, which make pins mandatory.

So, here's my conceptual idea: instead of relying on pins for generating queues and routing keys in the AMQP world, I'd like to use the actual action patterns.

For instance, in a simple scenario with a microservice containing:

# listener.js
require('seneca')()
  .use('seneca-amqp-transport')
  .add('cmd:salute', function(req, done) {
    return done(null, { message: `${Hello req.name}!` });
  });
  .add('cmd:sum', function(req, done) {
    return done(null, { sum: req.a + req.b });
  })
  .add('cmd:log,level:*', function(req, done) {
    console[req.level](req.message);
    return done(null, { ok: true });
  });

I'd like to generate one AMQP queue bound to some topic exchange with routing keys cmd.salute, cmd.sum, cmd.log.level.*. The thing is, I wasn't able to find a way to obtain all those patterns at plugin initialization. I know seneca.list() returns an array of all declared topics, but that also includes all "internal" patterns (like role:transport,hook:listen or role:seneca,cmd:close) - I'm only interested in "user defined" actions, and AFAIK there's no way to distinguish those from others. There's also no event emitted when adding an action to the actmap I could potentially listen to.

One approach I could think of is defining some actmeta.plugin_name when declaring actions, such as:

require('seneca')()
  .use('seneca-amqp-transport')
  .add('cmd:salute', function(req, done) {
    return done(null, { message: `${Hello req.name}!` });
  }, { plugin_name: 'amqp-transport' });

And then leverage private$.stats.actmap to query for acts containing that name. But it's (very) far from an ideal solution.

Any thoughts on this? It'd be much appreciated.

@nfantone
Copy link
Collaborator Author

A second approach would be to seneca.decorate the global instance of Seneca and define a new function that could register the queue and whatnot, serving as a drop-in replacement for add. Something like,

require('seneca')()
  .use('seneca-amqp-transport')
  // Replaced `.add` with `.amqpAdd`, which internally calls `.add`.
  .amqpAdd('cmd:salute', function(req, done) {
    return done(null, { message: `${Hello req.name}!` });
  });

Again, not a perfect solution. And would bring over transport incompatibilities and other issues to the table.

@nfantone
Copy link
Collaborator Author

nfantone commented Oct 17, 2016

@mcdonnelldean Know anyone that could help me on this? I'm willing to send a PR if this is not at all possible in Seneca, provided someone could give me some advice.

@nfantone
Copy link
Collaborator Author

nfantone commented Nov 4, 2016

TL;DR I want to know which pattern is being added by the user when calling .add, either at the time of the call (via a hook or event, possibly) or later at Seneca initialization.

@senecajs/collaborators Anyone?

@brad-decker
Copy link

@nfantone the concept of the pins confuses me slightly. In my api network will i need to create a new client instance for every microservice I want to hit that has a pin that matches the pin of the microservice i want it to interact with?

@nfantone
Copy link
Collaborator Author

nfantone commented Jul 15, 2017

@brad-decker Yes and no. Yes, you need a client with a pin that matches a certain listener's pin. No, it doesn't need to be a one-to-one match.

Think of pins as the "gateway" or entrance to your listener. They actually become the routing keys in your AMQP topology. Any pattern that matches a certain pin would be consumed by the listener declaring that pin. After they match, the message would be routed to the listener where it'd be then compared against the different actions it has added.

  • The pin of a listener says "I'm going to listen to all messages that are published with this routing key".

  • The pin of a client says "I'm going to publish messages using this routing key".

Take a look at this example. The pin 'action:get_time', 'level:*', 'proc:status' matches patterns like 'level:log', 'level:info' or 'proc:status' and any client can act on them as long as they declare a matching pin for the route they are interested in (say, for example, 'level:info' only, or 'level:*').

@nfantone
Copy link
Collaborator Author

@brad-decker I'd like to point out that I also think pins are confusing, rather redundant and, ultimately, not really needed. This is the reason why this issue was opened in the first place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants