Articles

Epers, Erlang, and Domain Events when persisting your entities


Introduction

In the last article, I presented epers, a small project intended to help build erlang applications that need to persist entities to a database.

In this new article, I'll describe the built-in domain events available in the framework.

How it works

Whenever epers is requested to do certain operations and if they succeed, an event will be dispatched using gen_event:notify/2.

You should start your own event manager (by using any of start_link/0, start_link/1, start/0, start/1), register whatever event handlers you need, and epers will always try to dispatch the interesting events through it, but wont fail if it's not present.

Configuring epers

The event manager (i.e: gen_event process) reference to be used goes straight into the epers configuration. Let's look at the example blog.config file, in the example application shipped with epers. You will notice something like:

  ...
  {events, [
    {blog_post, my_event_bus}
  ]},
  ...

This simple line of configuration states that for the entity blog_post we want to dispatch events to the my_event_bus gen_event reference.

Note that there wont be any events dispatched for the missing entities. So in the end, you specifically estipulate what entities you'd like to receive events for, and the specific event manager where these events will be dispatched to.

As the gen_event manual states, an event manager reference can be any of:

  • a pid()
  • Name (an atom(), if the event manager was registered with {local, Name})
  • {global, GlobalName}
  • {Name, Node}

Available domain events

All events are dispatched including the entity name (user, blog_post, etc), and a list of terms that are additional arguments for the event. Here's a complete list:

  • schema_created: Dispatched by epers:create_schema, without arguments ([]).
  • created: Dispatched by epers:persist when persisting new entities. [Entity] is sent along as arguments, containing a proplist with all the current properties.
  • updated: Dispatched by epers:persist when persisting an already existant entity. [Entity] is sent along as arguments, containing a proplist with all the current properties.
  • deleted: Dispatched by epers:delete when deleting an entity. [Id] is sent along as arguments.
  • deleted_all: Dispatched by epers:delete_all.

Handling domain events

A complete example is available with the example application, here. The interesting bits of code are:

...
handle_event({blog_post, schema_created, []}, State) ->
  lager:info("The blog post schema has been created"),
  {ok, State};

handle_event({blog_post, deleted, [Id]}, State) ->
  lager:info("The blog post ~p has been deleted", [Id]),
  {ok, State};

handle_event({blog_post, deleted_all, []}, State) ->
  lager:info("All blog posts entries have been deleted"),
  {ok, State};

handle_event({blog_post, created, [Entity]}, State) ->
  Id = proplists:get_value(id, Entity),
  lager:info("Blog post ~p created", [Id]),
  {ok, State};

handle_event({blog_post, updated, [Entity]}, State) ->
  Id = proplists:get_value(id, Entity),
  lager:info("Blog post ~p updated", [Id]),
  {ok, State};
...

Conclusion

Having this feature in epers allows you to create alerts, trigger specific jobs, maybe even create tweets, or notify web clients through websockets that something interesting happened in the system, without much effort, so it's kind of a cool thing to have around and I hope you enjoy it :)