EctoWatch

EctoWatch allows you to easily get Phoenix.PubSub notifications directly from postgresql.

Often in Elixir applications a Phoenix.PubSub.broadcast is sent to notifiy other parts of the application that an insert, update, or deletion has occurred. This has a few problems:

EctoWatch solves these problems by getting updates directly from postgresql. This ensures that messages are sent for every update. EctoWatch also establishes a simple standardized set of messages for inserts, updates, and deletes so that there can be consistency across your application.

Usage

To use EctoWatch, you need to add it to your supervision tree and specify the ecto schemas that you want to monitor. You can do this by adding something like the following to your application.ex file (after your MyApp.Repo and MyApp.PubSub are loaded):

{EctoWatch, {MyApp.Repo, MyApp.PubSub, [
MyApp.Accounts.User,
{MyApp.Shipping.Package, [:inserted, :updated]}
]}},

This will setup:

Then any process (e.g. a GenServer, a LiveView, or a Phoenix channel) can subscribe to messages like so:

EctoWatch.subscribe(MyApp.Accounts.User, :inserted)
EctoWatch.subscribe(MyApp.Accounts.User, :updated)
EctoWatch.subscribe(MyApp.Accounts.User, :deleted)
EctoWatch.subscribe(MyApp.Shipping.Package, :inserted)
EctoWatch.subscribe(MyApp.Shipping.Package, :updated)

(note that if you are subscribing in a LiveView mount callback you should subscribe inside of a if connected?(socket) do block to avoid subscribing twice).

You can also subscribe to individual records:

EctoWatch.subscribe(MyApp.Accounts.User, :updated, user.id)
EctoWatch.subscribe(MyApp.Accounts.User, :deleted, user.id)

Once a process is subscribed messages can be handled like so (LiveView example given here but handle_info callbacks can be used elsewhere as well):

def handle_info({:inserted, MyApp.Accounts.User, id}, socket) do
user = Accounts.get_user(id)
socket = stream_insert(socket, :users, user)
{:noreply, socket}
end
def handle_info({:updated, MyApp.Accounts.User, id}, socket) do
user = Accounts.get_user(id)
socket = stream_insert(socket, :users, user)
{:noreply, socket}
end
def handle_info({:deleted, MyApp.Accounts.User, id}, socket) do
user = Accounts.get_user(id)
socket = stream_delete(socket, :users, user)
{:noreply, socket}
end

Installation

If available in Hex, the package can be installed by adding ecto_watch to your list of dependencies in mix.exs:

def deps do
[
{:ecto_watch, "~> 0.1.0"}
]
end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/ecto_watch.