Standalone Event Dispatcher

From @geoffjukes on Sat Aug 12 2017 05:18:58 GMT+0000 (UTC)

Hi,

The docs for the standalone event dispatcher need to be updated (I think). I trawled the code, and figured the following works (for me)

I’m aiming to send a ‘ping’ event to all services (just like the example in the events docs).

Is there an easier/more efficient way to do what I’m doing? or is this pretty much spot on?

from nameko.standalone.events import event_dispatcher
from nameko.dependency_providers import Config
from nameko_slack import rtm

class Slack:
    name = 'slackbot'
    config = Config()

    def dispatch(self, service_name, event_type, event_data):
        event_dispatcher(self.config)(service_name, event_type, event_data)

    @rtm.handle_message('status')
    def on_status(self, event, message):
        self.dispatch("monitor", "ping", event['channel'])

Incidentally - I am a massive fan of Nameko.

Copied from original issue: https://github.com/nameko/nameko/issues/464

From @mattbennett on Mon Aug 14 2017 12:50:03 GMT+0000 (UTC)

Hi Geoff,

Thanks :grinning:

Your code is valid, but perhaps isn’t the best way of achieving your goal. Events are intended to be dispatched from an originating service, and handled in any “interested” subscribing services. The standalone dispatcher is a helper for “faking” that behaviour when needed (e.g. in tests) or to originate events from non-nameko services.

The code above will send a “ping” event claiming to originate from a “monitor” service. It is valid, but breaks the (implicit and undocumented!) intention that events are sourced at real services.

Assuming the aim is to get all services to do something when the “status” command is issued in slack, I would do it by dropping down to the lower-level “messaging” extensions that events are built on top of.

Nameko events are little more than a particular configuration of underlying elements of AMQP (the exchanges, queues, bindings, routing keys and consumers). For your use-case you probably want to configure these elements slightly differently.

I guess you want a single exchange that all services bind a queue to, and a consumer in each service instance. This is basically what you get with broadcast events, but doing it yourself you can control the exchange name, routing keys and queue names.

Something like this:

# slackbot
from nameko.messaging import Publisher
from kombu.messaging import Exchange

monitoring_exchange = Exchange(name="monitoring")

class Slack:
    name = 'slackbot'
    config = Config()

    publish = Publisher(exchange=monitoring_exchange)

    @rtm.handle_message('status')
    def on_status(self, event, message):
        self.publish(routing_key="ping", event['channel'])
# service_x.py
from nameko.messaging import consume
from kombu.messaging import Exchange, Queue

monitoring_exchange = Exchange(name="monitoring")

ping_queue = Queue(name="<unique-name>", routing_key="ping", exchange="monitoring")

class Service:
    name = "x"

    @consume(queue=ping_queue)
    def handle_ping(self, payload):
        pass

1 Like