Elixir: Writing your own Event Dispatcher

Sergey Radzishevskii
3 min readJan 16, 2019

--

Today we are going to learn how you could build your own implementation of event dispatcher in Elixir.

NOTE: if you are looking for production-ready implementation please review “:event_bus”. This article is educational. We are not going to build a production-ready solution. Although… how knows :)

elixir event dispatcher

What would be our event dispatcher? It is a separate process that would listen for messages from the main application process and handle received events via subscribed listeners and subscribers.

I will call our main process :main and our event dispatcher process is :ed.

Start new event dispatcher process

Please review GenServer docs before moving forward. It’s crucial to understand how things work.

Now let’s make a skeleton for event dispatcher

We use GenServer and going to start a new process with start_link/3and give a unique name to our process. So far, our name will be our __MODULE__ name but we will change it later. It will allow us to run many event dispatchers. Also

Note that a GenServer started with start_link/3 is linked to the parent process and will exit in case of crashes from the parent

Add subscribers and listeners

Ok, our process up and running but it’s dummy. We want to subscribe listeners and subscribers for our event dispatcher.

We add 2 client functions add_subscriber/1 and add_listeners/3. They will send a message from :main process to our :ed process. GenServer.call(my_name(), ... will send it to :ed process. Our unique name will help to send the signal to the right process.

And server handle_call/3 functions will be performed in :ed process. I’m using Rsed.ListenerBag module, it will add new listeners and subscribers to a map like this.

It allows us to merge/combine and order subscribers and listeners. When we need to dispatch an event all we need to do just go through the list of all event listeners(listeners and subscribers). They are already ordered.

Dispatch event

Now we have subscribers and listeners and can dispatch an event.

In a similar way, we expose client and server functions. We ask ListenerBag for listeners for a certain event name. And then just call handlers.

Usage in your application

How we can use it in our application? We need to add our :ed process to our supervisor

But in that case, we also would need to configure it at the start but I don’t really like to do that in the Application module. And also we cannot run more than 1 :ed process because of its name not really unique and will refer to our module name Rsed.EventDispatcher. So I’m going to make one more iteration that will allow auto-configure it and

We wrap our functions with __using__ and quote and now can use :name that would be set in use call. It will allow us to run multiple :ed processes if needed. And also in init function we add a logic that will call configure function if it presents.

Note that we cannot call add_subscriber/1 and add_listener/3 — because it’s client function and we call it on a server-side or inside :ed process. Now we update our supervisor spec with our custom app event dispatcher.

worker(App.EventDispatcher, [])# in your appApp.EventDispatcher.dispatch(%Rsed.Event{name: :user_registered, data: user})# BINGO

Source

You can find the source code here https://github.com/radzserg/rsed

What is missing

  • stop event propagation
  • dynamic remove of subscribers and listeners
  • synchronous handling
  • proper testing in production

If you like that topic and want to contribute DM and let’s do it.

--

--

Sergey Radzishevskii
Sergey Radzishevskii

Written by Sergey Radzishevskii

Enjoy turning complex systems into intelligible architectures chilling in my garden.

No responses yet