Packages
ecto
1.1.8
3.14.1
3.14.0
3.13.6
3.13.5
3.13.4
3.13.3
3.13.2
3.13.1
3.13.0
3.12.6
3.12.5
3.12.4
3.12.3
3.12.2
3.12.1
3.12.0
3.11.2
3.11.1
3.11.0
3.10.3
3.10.2
3.10.1
3.10.0
3.9.6
3.9.5
3.9.4
3.9.3
3.9.2
3.9.1
3.9.0
3.8.4
3.8.3
3.8.2
3.8.1
3.8.0
3.7.2
3.7.1
3.7.0
3.6.2
3.6.1
3.6.0
3.5.8
3.5.7
3.5.6
3.5.5
3.5.4
3.5.3
3.5.2
3.5.1
3.5.0
3.5.0-rc.1
3.5.0-rc.0
3.4.6
3.4.5
3.4.4
3.4.3
3.4.2
3.4.1
3.4.0
3.3.4
3.3.3
3.3.2
3.3.1
3.3.0
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.1.7
3.1.6
3.1.5
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.9
3.0.8
3.0.7
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
3.0.0-rc.1
3.0.0-rc.0
2.2.12
2.2.11
2.2.10
2.2.9
2.2.8
2.2.7
2.2.6
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.2.0-rc.1
2.2.0-rc.0
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.1.0-rc.5
2.1.0-rc.4
2.1.0-rc.3
2.1.0-rc.2
2.1.0-rc.1
2.1.0-rc.0
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
2.0.0-rc.6
2.0.0-rc.5
2.0.0-rc.4
2.0.0-rc.3
2.0.0-rc.2
2.0.0-rc.1
2.0.0-rc.0
2.0.0-beta.2
2.0.0-beta.1
2.0.0-beta.0
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.16.0
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
0.13.0
0.12.1
0.12.0
0.12.0-rc
0.11.3
0.11.2
0.11.1
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.0
0.5.1
0.5.0
0.4.0
0.3.0
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.0
A toolkit for data mapping and language integrated query for Elixir
Current section
Files
Jump to
Current section
Files
lib/ecto/pools/poolboy/worker.ex
defmodule Ecto.Pools.Poolboy.Worker do
@moduledoc false
use GenServer
use Behaviour
require Logger
alias Ecto.Adapters.Connection
@type modconn :: {module :: atom, conn :: pid}
@spec start_link({module, Keyword.t}) :: {:ok, pid}
def start_link({module, params}) do
GenServer.start_link(__MODULE__, {module, params}, [])
end
@spec checkout(pid, fun, timeout) ::
{:ok, modconn} | {:error, Exception.t} when fun: :run | :transaction
def checkout(worker, fun, timeout) do
GenServer.call(worker, {:checkout, fun}, timeout)
end
@spec checkin(pid) :: :ok
def checkin(worker) do
GenServer.cast(worker, :checkin)
end
@spec break(pid, timeout) :: :ok
def break(worker, timeout) do
GenServer.call(worker, :break, timeout)
end
## Callbacks
def init({module, opts}) do
Process.flag(:trap_exit, true)
{opts, params} = Keyword.split(opts, [:lazy, :shutdown])
lazy? = Keyword.get(opts, :lazy, true)
shutdown = Keyword.get(opts, :shutdown, 5_000)
unless lazy?, do: GenServer.cast(self(), :connect)
{:ok, %{conn: nil, params: params, shutdown: shutdown, transaction: nil,
module: module}}
end
## Break
def handle_call(:break, _from, s) do
s = s
|> demonitor()
|> disconnect()
{:reply, :ok, s}
end
## Lazy connection handling
def handle_call(request, from, %{conn: nil, params: params, module: module} = s) do
case Connection.connect(module, params) do
{:ok, conn} -> handle_call(request, from, %{s | conn: conn})
{:error, err} -> {:reply, {:error, err}, s}
end
end
## Checkout/Open transaction when in transaction
def handle_call({:checkout, _} = checkout, from, %{transaction: {client, _}} = s) do
if Process.alive?(client) do
{:stop, :bad_checkout, s}
else
# poolboy got the :DOWN message and checked out this process to a new
# client before this process got the :DOWN from the old client
s = s
|> demonitor()
|> disconnect()
handle_call(checkout, from, s)
end
end
## Checkout
def handle_call({:checkout, :run}, _, %{transaction: nil} = s) do
{:reply, {:ok, modconn(s)}, s}
end
## Open transaction
def handle_call({:checkout, :transaction}, from, %{transaction: nil} = s) do
{pid, _} = from
{:reply, {:ok, modconn(s)}, monitor(pid, s)}
end
## Close transaction
def handle_cast(:checkin, %{transaction: nil} = s) do
{:stop, :notransaction, s}
end
def handle_cast(:checkin, s) do
{:noreply, demonitor(s)}
end
def handle_cast(:connect, %{conn: nil, transaction: nil} = s) do
%{module: module, params: params} = s
case Connection.connect(module, params) do
{:ok, conn} ->
{:noreply, %{s | conn: conn}}
{:error, error} ->
log_connect_error(error, s)
{:noreply, s}
end
end
## Info
# The connection crashed. We don't need to notify
# the client if we have an open transaction because
# it will fail with noproc anyway.
def handle_info({:EXIT, conn, _reason}, %{conn: conn} = s) do
s = %{s | conn: nil}
|> disconnect()
{:noreply, s}
end
# The transaction owner crashed without closing.
# We need to assume we don't know the connection state.
def handle_info({:DOWN, ref, _, _, _}, %{transaction: {_, ref}} = s) do
{:noreply, disconnect(%{s | transaction: nil})}
end
def handle_info(_info, s) do
{:noreply, s}
end
def terminate(_reason, s), do: disconnect(s)
## Helpers
defp modconn(%{conn: conn, module: module}) do
{module, conn}
end
defp monitor(pid,s) do
ref = Process.monitor(pid)
%{s | transaction: {pid, ref}}
end
defp demonitor(%{transaction: nil} = s), do: s
defp demonitor(%{transaction: {_, ref}} = s) do
Process.demonitor(ref, [:flush])
%{s | transaction: nil}
end
defp disconnect(%{conn: conn, shutdown: shutdown} = s) do
_ = conn && Connection.shutdown(conn, shutdown)
%{s | conn: nil}
end
defp log_connect_error(error, %{module: module, params: params}) do
Logger.error(fn() ->
[inspect(module), " failed to connect with parameters ", inspect(params),
?\n | inspect_error(error)]
end)
end
defp inspect_error({'EXIT', reason}) do
Exception.format_exit(reason)
end
defp inspect_error(reason) do
if Exception.exception?(reason) do
Exception.format_banner(:error, reason)
else
Exception.format_banner(:exit, reason)
end
end
end