Skip to content

gmtprime/yggdrasil_postgres

Repository files navigation

Yggdrasil for PostgreSQL

Build Status Hex pm hex.pm downloads

Yggdrasil for PostgreSQL is a publisher/subscriber that:

  • It's easy to use and configure.
  • It's fault tolerant: recovers disconnected subscriptions.
  • It has reconnection support: configurable exponential backoff.
  • It has OS environment variable configuration support (useful for releases).

Small example

The following example uses PostgreSQL adapter to distribute messages e.g:

Given the following channel:

iex> channel = [name: "pg_channel", adapter: :postgres]

You can:

  • Subscribe to it:

    iex> Yggdrasil.subscribe(channel)
    iex> flush()
    {:Y_CONNECTED, %Yggdrasil.Channel{...}}
  • Publish messages to it:

    iex> Yggdrasil.publish(channel, "message")
    iex> flush()
    {:Y_EVENT, %Yggdrasil.Channel{...}, "message"}
  • Unsubscribe from it:

    iex> Yggdrasil.unsubscribe(channel)
    iex> flush()
    {:Y_DISCONNECTED, %Yggdrasil.Channel{...}}

And additionally, you can use Yggdrasil behaviour to build a subscriber:

defmodule Subscriber do
  use Yggdrasil

  def start_link do
    channel = [name: "pg_channel", adapter: :postgres]
    Yggdrasil.start_link(__MODULE__, [channel])
  end

  @impl Yggdrasil
  def handle_event(_channel, message, _) do
    IO.inspect message
    {:ok, nil}
  end
end

The previous Subscriber will print every message that comes from the PostgreSQL channel pg_channel.

PostgreSQL adapter

The PostgreSQL adapter has the following rules:

  • The adapter name is identified by the atom :postgres.
  • The channel name must be a string.
  • The transformer must encode to a string. From the transformers provided, it defaults to :default, but :json can also be used.
  • Any backend can be used (by default is :default).

The following is an example of a valid channel for both publishers and subscribers:

%Yggdrasil.Channel{
  name: "pg_channel",
  adapter: :postgres,
  transformer: :json
}

The previous channel expects to:

  • Subscribe to or publish to the channel pg_channel.
  • The adapter is :postgres, so it will connect to PostgreSQL using the appropriate adapter.
  • The transformer expects valid JSONs when decoding (consuming from a subscription) and map() or keyword() when encoding (publishing).

Note: Though the struct Yggdrasil.Channel is used. keyword() and map() are also accepted as channels as long as the contain the required keys.

PostgreSQL configuration

This adapter supports the following list of options:

Option Default Description
hostname "localhost" PostgreSQL hostname.
port 5432 PostgreSQL port.
username "postgres" PostgreSQL username.
password "postgres" PostgreSQL password.
database "postgres" PostgreSQL database.
max_retries 3 Amount of retries where the backoff time is incremented.
slot_size 10 Max amount of slots when adapters are trying to reconnect.
subscriber_connections 1 Amount of subscriber connections.
publisher_connections 1 Amount of publisher connections.

Note: Concurrency is handled by Postgrex subscriptions in order to reuse database connections.

For more information about the available options check Yggdrasil.Settings.Postgres.

The following shows a configuration with and without namespace:

# Without namespace
config :yggdrasil,
  postgres: [hostname: "postgres.zero"]

# With namespace
config :yggdrasil, PostgresOne,
  postgres: [
    hostname: "postgres.one",
    port: 1234
  ]

All the available options are also available as OS environment variables. It's possible to even separate them by namespace e.g:

Given two namespaces, the default one and Postgres.One, it's possible to load the hostname from the OS environment variables as follows:

  • $YGGDRASIL_POSTGRES_HOSTNAME for the default namespace.
  • $POSTGRES_ONE_YGGDRASIL_POSTGRES_HOSTNAME for Postgres.One.

In general, the namespace will go before the name of the variable.

Installation

Using this adapter with Yggdrasil is a matter of adding the available hex package to your mix.exs file e.g:

def deps do
  [{:yggdrasil_postgres, "~> 5.0"}]
end

Running the tests

A docker-compose.yml file is provided with the project. If you don't have a PostgreSQL server, but you do have Docker installed, then you can run:

$ docker-compose up --build

And in another shell run:

$ mix deps.get
$ mix test

Author

Alexander de Sousa.

License

Yggdrasil is released under the MIT License. See the LICENSE file for further details.