Current section
Files
Jump to
Current section
Files
lib/yggdrasil/postgres/connection/generator.ex
defmodule Yggdrasil.Postgres.Connection.Generator do
@moduledoc """
This module defines a supervisor for creating connection pools on demand.
"""
use DynamicSupervisor
alias Yggdrasil.Postgres.Connection
alias Yggdrasil.Postgres.Connection.Pool
@doc """
Starts a connection pool generator.
"""
@spec start_link() :: Supervisor.on_start()
@spec start_link(DynamicSupervisor.options()) :: Supervisor.on_start()
def start_link(options \\ []) do
DynamicSupervisor.start_link(__MODULE__, nil, options)
end
@doc """
Stops a connection pool `generator`. Optionally, it receives a `reason`
(defaults to `:normal`) and a `timeout` (default to `:infinity`).
"""
@spec stop(Supervisor.supervisor()) :: :ok
@spec stop(Supervisor.supervisor(), term()) :: :ok
@spec stop(Supervisor.supervisor(), term(), :infinity | non_neg_integer()) ::
:ok
defdelegate stop(generator, reason \\ :normal, timeout \\ :infinity),
to: DynamicSupervisor
@doc """
Gets a connection for a `tag` and a `namespace`.
"""
@spec get_connection(Connection.tag(), Connection.namespace()) ::
{:ok, pid()} | {:error, term()}
def get_connection(tag, namespace)
def get_connection(tag, namespace) do
with {:ok, _} <- connect(__MODULE__, tag, namespace) do
Pool.get_connection(tag, namespace)
else
{:error, {:already_started, _}} ->
Pool.get_connection(tag, namespace)
error ->
error
end
end
############################
# DynamicSupervisor callback
@impl true
def init(_) do
DynamicSupervisor.init(strategy: :one_for_one)
end
#########
# Helpers
@doc false
@spec connect(
Supervisor.supervisor(),
Connection.tag(),
Connection.namespace()
) :: DynamicSupervisor.on_start_child()
def connect(generator, tag, namespace)
def connect(generator, tag, namespace) do
name = gen_pool_name(tag, namespace)
case ExReg.whereis_name(name) do
:undefined ->
specs = gen_pool_specs(name, tag, namespace)
DynamicSupervisor.start_child(generator, specs)
pid when is_pid(pid) ->
{:ok, pid}
end
end
##
# Generates the pool name.
defp gen_pool_name(tag, namespace) do
{__MODULE__, tag, namespace}
end
##
# Generates the pool spec.
defp gen_pool_specs(name, tag, namespace) do
via_tuple = ExReg.local(name)
%{
id: via_tuple,
type: :supervisor,
restart: :transient,
start: {Pool, :start_link, [tag, namespace, [name: via_tuple]]}
}
end
end