Just released Ecto.Observable - an easy way to bring “observable” functionality to your Ecto.Repo’s. Hook into the life cycle of your records to expand features without muddying your contexts.
Check it out at: Ecto.Observable
Work in progress! PR’s and suggestions welcome!
For note, unless explicitly stated by a parent project it’s usually best not to choose a submodule inside a parent project as your name (like
Ecto.Observable) and instead just concat them (
EctoObservable) so you don’t have to worry about namespace collisions later.
Interesting pattern though, does it work transactionally?
Nice library! I’d use something like this whenever
Postgrex.Notifications wasn’t available.
Some ideas based on a quick skim of the code, apologies in advance if I’ve misunderstood something:
- It appears that observers are notified before an enclosing transaction is comitted:
This can cause problems if the observers have side effects like sending emails, publishing to message queues, etc.
The observers all run sequentially in the same process as the caller. This may not be ideal if they perform long operations. Something like
Task.Supervisor.async_stream_no_link could be used to execute them concurrently in separate processes.
It looks like observers need to be stateless, this can make it tricky when you want the similar functionality in two observers with slightly different configuration. Something like the
Plug.init callback that allows some context to be passed in to the observer would be useful. Another pattern I like would be to make Observer a protocol. You can provide an implementation for
atom for stateless module based observers.
Thanks for the feedback!
@OvermindDL1 - I released a new version that removes the Ecto namespace from the library. All the additional repo actions are wrapped in a transaction.
@mbuhot - thanks for the comments.
I have worked with
Postgrex.Notifications a little bit as well. Although I like the idea of handling the data at the time of action a little bit more. Its already in struct form, and is easy to pattern match against without having to do additional encoding.
Correct me if I’m wrong, but notifications would return it in json form no? Also - if you have multiple boxes running - I assume you have to ensure the listener is running as a global process if you dont want every box to take action on a notification. I’m wondering if this would ever become a bottleneck? One could implement a pool under this if needed obviously.
I debated whether to implement each observer callback as an async process. In the end, I decided to let the user decide what they want - with the callback implementing any async functionality. Although perhaps something like
insert_and_async_notify/2 would be nice.
Will look into #3!