Qqwy

Qqwy

TypeCheck Core Team

TeaVent: Library for Event-Sourcing/The Elm Architecture (WIP)

I am working on a new library called TeaVent(hex.pm.

It allows you to perform event-dispatching in a way that is a blend of Event-Sourcing and The Elm Architecture.

Rather than copy the documentation here verbatim, you can read it here, but as a quick Tl;Dr:

  • All events that come in are normalized, and then go through the reducer (event handler)-function configured by you. This allows events to modify the state of your system. The reducer is a pure function, which allows for easy reasoning and testing (including property-based tests).
  • Around this, you can add a context_provider, which, can transform your application state to look up that part that is significant for the current event. This allows you to use large systems that have databases, store something in GenServers, are distributed etc. to work with the system as well. (Instead of having a ‘single source of truth’ the ContextProvider sets up a ‘single source of truth for this event’) and after running the reducer, is able to use the results of the reducer-call to e.g. store it back in the database. Because this is separate from the reducer, it can be tested separately!.
  • Around this, you can add middleware to do instrumentation, or add things like database-transactions (doing these here mean that the ContextProvider can use a declarative db-interaction-style like e.g. Ecto.Multi, which again makes things easier to test!).
  • You can decide on different configurations for different environments, or a different one per-test, etc: Configuration is done in the final parameter passed to TeaVent.dispatch, or in the Application.env, falling back to some sensible defaults whenever possible, and raising errors on missing required options, or unknown options. This is based on the discussion on making better configurations in libraries.

The library strives to cater to each of the following needs:

  • ‘full’ Event Sourcing where events are always made and persisted, and the state-changes are done asynchroniously (and potentially there are multiple state-representations (i.e. event-handlers) working on the same queue of events).
  • a ‘classical’ relational-database setup where this can be treated as single-source-of-truth, and events/state-changes are only persisted when they are ‘valid’.
  • a TEA-style application setup, where our business-domain model representation changes in a pure way.
  • A distributed-database setup where it is impossible to view your data-model as a ‘single-source-of-truth’ (making database-constraints impossible to work with), but the logical contexts of most events do not overlap, which allows us to handle constraints inside the application logic that is set up in TEA-style.

What is missing from the current version is:

  • Better documentation for the current example.
  • A proper example (e.g. an example project) of how to use it with e.g. Ecto.
  • An even simpler ‘hello-world’ example that could be put in the documentation (/doctests).
  • Tests of all the bells and whistles.
  • Fixing all typespecs and making sure Dialyzer is happy with them.

And of course I am very eager to hear feedback from you!

Most Liked

OvermindDL1

OvermindDL1

Aww, wish this existed 6 months ago, I basically wrote this in an Elixir bot that I wrote a long while back (although mine is introspectable and hot updateable via database mappings for web interface modification on-the-fly). ^.^;

EDIT: Just brought up my code, here are some ideas from it if you want to rip them out:

Dispatch an event:

EventPipe.inject(who, data)

The who is ran through a ProtocolEx protocol to translate it to an internal EventPipe structure, it accepts a variety of inputs from a Plug.Conn to grab the session data, Discord user, IRC user, system console, etc…

Once that conversion is complete then it ‘injects’ (dispatch is such a better name…) the data through the ‘pipeline’, which looks up in the database cache the MFA tuples, performs a set of checks, I have a matcher’ish-like syntax that is defined in the web browser interface for testing which should handle which type of thing, and all top-level matching event handlers of the auth/data combination get called with the data in the order of their priority (I always intended to auto-generate a ProtocolEx matcher module based on the database matchers but never got around to it).

Each of those matchers can then either handle the event auth/data as they wish, potentially (and often) re-injecting/dispatching more messages into the system (I don’t check for endless loops, it’s possible to happen, but as it’s only for my use I haven’t worried about such things as of yet), such as if someone sends a command or a webhook is called from github then it can dispatch a message to display (in a variety of rich and non-rich formats) to display in IRC, Discord, and websocket to a web-browser.

In addition its introspectable interface is like this:

# Add an event hook into the system, the database_name is a distinguisher so you can have multiple dispatching systems)
EventPipe.add_hook(database_name \\ :global, priority, matchers, extended_matchers, module, function, args)

# Delete a hook structure from the database, the structure you can get via `get_hooks` or so
EventPipe.delete_hook(database_name \\ :global, cb)

# Get all the hook structures from the database so you can display in an admin page, edit, modify, delete, whatever
EventPipe.get_hooks(database_name \\ :global)

And there is a variety of helper functions.

Qqwy

Qqwy

TypeCheck Core Team

What would make you think that TeaVent would only allow one instance?

All configuration can be passed through the final argument to dispatch or dispatch_event, so you can have as many different set-ups as you wish. In fact, this is one of the main goals of this library, to allow you to have different set-ups in different parts of your test-suite!

danbruder

danbruder

This looks really appealing. Will check it out.

Where Next?

Popular in Announcing Top

wmnnd
Hi there, for my project DBLSQD, I needed a file storage solution that is a bit more flexible than Arc. Because I thought others might f...
New
josevalim
Hi everyone, We would like to announce that Plataformatec is working on a new MySQL driver called MyXQL. Our goal is to eventually integ...
New
bryanjos
Hi, I wanted share a small library we at Revelry Labs made for rendering react components from the server side. There are instructions fo...
New
sabiwara
Dune is a sandbox for Elixir and aims to safely evaluate user-provided code. You can try it out using this basic Elixir playground made ...
New
fuelen
Hey folks! Want to present a toolkit for writing command-line user interfaces. It provides a convenient interface for colorizing text...
New
michalmuskala
Hello everybody. I have just released Jason - a new JSON library. You might be wondering, why do we need a new library? The primary foc...
New
mplatts
With HEEX released we decided to start a components library using Tailwind CSS - check it out here: Petal Components. We also have a boi...
New
tmbb
I’ve decided to create this topic to discuss optimization possibilities for something like Phoenix LiveView. I’ve created this topic unde...
144 10462 141
New
handnot2
Samly can be used to enable SAML 2.0 Single Sign On in a Plug/Phoenix application. This library uses Erlang esaml to provide plug enabl...
New
trisolaran
Hi! :waving_hand: I would like to present LiveSelect, a little library that I wrote to easily add a dynamic selection input to your LV f...
198 10954 107
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29603 241
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 43487 311
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54120 245
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement