defmodule Sorcery.PubSub do @moduledoc """ Provides a clean interface for publishing and subscribing to events. ## Configuration In your config.exs: config :sorcery, :pub_sub, pub_sub: Sorcery.PubSub.PostgresStore, pub_sub_opts: [ repo: MyApp.Repo, table_name: "events" ] Or for in-memory storage: config :sorcery, :pub_sub, pub_sub: Sorcery.PubSub.MemoryStore ## Usage # Publish an event event = Sorcery.Event.new(%{ type: "user_registered", data: %{user_id: "123"}, domain: "users", instance_id: "instance_1", domain_sequence_number: 1 }) Sorcery.PubSub.publish(event) # Subscribe to events {:ok, events, pagination} = Sorcery.PubSub.subscribe() # Query specific events {:ok, events, pagination} = Sorcery.PubSub.subscribe_by_domain("users") {:ok, events, pagination} = Sorcery.PubSub.subscribe_by_type("user_registered") """ alias Sorcery.Event alias Sorcery.PubSub.Behaviour @type subscription :: Behaviour.subscription() def child_spec(opts) do %{ id: __MODULE__, start: {__MODULE__, :start_link, [opts]}, type: :worker, restart: :permanent, shutdown: 5000 } end @doc """ Publishes one or more events to the configured store. """ @spec publish(Event.t() | [Event.t()]) :: :ok | {:error, term()} def publish(events) do pub_sub().publish(events) end @doc """ Subscribes to events for a given subscription. """ @spec subscribe() :: :ok | {:error,term()} def subscribe() do pub_sub().subscribe() end @spec pub_sub() :: module() def pub_sub do Application.get_env(:sorcery, :pub_sub, []) |> Keyword.get(:pub_sub, Sorcery.PubSub.Registry) end @doc """ Returns the configured options for the pub sub. """ @spec pub_sub_opts() :: Keyword.t() def pub_sub_opts do Application.get_env(:sorcery, :pub_sub, []) |> Keyword.get(:pub_sub_opts, []) end @doc """ Starts the configured pub sub. """ @spec start_link(Keyword.t()) :: GenServer.on_start() def start_link(opts \\ []) do pub_sub().start(pub_sub_opts() ++ opts) end end