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 Libraries Top

hpopp
After just over two years in development, this latest version of Pigeon is what I finally consider done in regards to my original vision ...
New
devonestes
Introducing assertions, the library that helps you write really great test assertions! GitHub: https://github.com/devonestes/assertions ...
New
mindok
What is ContEx? A pure Elixir server-side data plotting/charting library outputting SVG. It has nice barcharts in particular and works g...
New
michalmuskala
Another small library today. PersistentEts Hex: persistent_ets | Hex GitHub: GitHub - michalmuskala/persistent_ets Ets table backed by...
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
tmbb
PhoenixWS - Websockets over Phoenix Channels Source code on Github here: https://github.com/tmbb/phoenix_ws Phoenix channels are a great...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 42633 214
New
bryanjos
Hi, I just published version 0.23.0 of Elixirscript. Most of the changes are around JavaScript interop now that Elixirscript uses the ...
New
Qqwy
While not as prevalent as in imperative languages, arrays (collections with efficient random element access) are still very useful in Eli...
New
anshuman23
Hello all, I have been working on my proposed project called Tensorflex as part of Google Summer of Code 2018.. Tensorflex can be used f...
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
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
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
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 27727 240
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New

Sub Categories:

We're in Beta

About us Mission Statement