db_connection v0.1.0 DBConnection behaviour
A behaviour module for implementing efficient database connection client processes, pools and transactions.
DBConnection
handles callbacks differently to most behaviours. Some
callbacks will be called in the calling process, with the state
copied to and from the calling process. This is useful when the data
for a request is large and means that a calling process can interact
with a socket directly.
A side effect of this is that query handling can be written in a simple blocking fashion, while the connection process itself will remain responsive to OTP messages and can enqueue and cancel queued requests.
If a request or series of requests takes too long to handle in the client process a timeout will trigger and the socket can be cleanly disconnected by the connection process.
If a calling process waits too long to start its request it will timeout and its request will be cancelled. This prevents requests building up when the database can not keep up.
If no requests are received for a period of time the connection will trigger an idle timeout and the database can be pinged to keep the connection alive.
Should the connection be lost, attempts will be made to reconnect with (configurable) exponential random backoff to reconnect. All state is lost when a connection disconnects but the process is reused.
The DBConnection.Query
and DBConnection.Result
protocols provide
utility functions so that queries can be prepared or encoded and
results decoding without blocking the connection or pool. Unless set
to :manual
these protocols will be called automatically at the
appropriate moment.
By default the DBConnection
provides a single connection. However
the :pool_mod
option can be set to use a pool of connections. If a
pool is used the module must be passed as an option - unless inside a
run/3
or transaction/3
fun and using the run/transaction
connection reference (t
).
Summary
Functions
Create a supervisor child specification for a pool of connections
Close a prepared query on a database connection and return :ok
on
success or {:error, exception}
on error
Close a prepared query on a database connection and return :ok
.
Raises an exception on error
Execute a prepared query with a database connection and return
{:ok, result}
on success or {:error, exception}
if there was an
error
Execute a prepared query with a database connection and return the result. Raises an exception on error
Prepare a query with a database connection for later execution and
returns {:ok, query}
on success or {:error, exception}
if there was
an error
Prepare a query with a database connection and return the prepared query. An exception is raised on error
Run a query with a database connection and returns {:ok, result}
on
success or {:error, exception}
if there was an error
Run a query with a database connection and return the result. An exception is raised on error
Rollback a transaction, does not return
Acquire a lock on a connection and run a series of requests on it. The
result of the fun is return inside an :ok
tuple: {:ok result}
Start and link to a database connection process
Acquire a lock on a connection and run a series of requests inside a
tranction. The result of the transaction fun is return inside an :ok
tuple: {:ok result}
Macros
Use DBConnection
to set the behaviour and include default
implementations for handle_prepare/3
(no-op), handle_execute/3
(forwards to handle_query
) and handle_close/3
(no-op) for
connections that don’t handle the prepare/execute/close pattern.
handle_info/2
is also implemented as a no-op
Callbacks
Checks in the state to the connection process. Return {:ok, state}
to allow the checkin or {:disconnect, exception}
to disconnect
Checkouts the state from the connection process. Return {:ok, state}
to allow the checkout or `{:disconnect, exception} to disconnect
Connect to the databases. Return {:ok, state}
on success or
{:error, exception}
on failure
Disconnect from the database. Return :ok
Handle the beginning of a transaction. Return {:ok, state}
to
continue, {:error, exception, state}
to abort the transaction and
continue or {:disconnect, exception, state}
to abort the transaction
and disconnect
Close a query prepared by handle_prepare/3
with the database. Return
{:ok, state}
on success and to continue,
{:error, exception, state}
to return an error and continue, or
{:disconnect, exception, state}
to return an error and disconnect
Handle commiting a transaction. Return {:ok, state}
on success and
to continue, {:error, exception, state}
to abort the transaction and
continue or {:disconnect, exception, state}
to abort the transaction
and disconnect
Execute a query prepared by handle_prepare/3
. Return
{:ok, result, state}
to return the result result
and continue,
{:error, exception, state}
to return an error and continue or
{:disconnect, exception, state{}
to return an error and disconnect
Handle a message received by the connection process when checked in.
Return {:ok, state}
to continue or `{:disconnect, exception,
state}` to disconnect
Handle a query. Return {:ok, result, state}
to return the result
result
and to continue, {:error, exception, state}
to return an
error and to continue and {:disconnect, exception, state}
to return
an error and to disconnect
Handle rolling back a transaction. Return {:ok, state}
on success
and to continue, {:error, exception, state}
to abort the transaction
and continue or {:disconnect, exception, state}
to abort the
transaction and disconnect
Called when the connection has been idle for a period of time. Return
{:ok, state}
to continue or {:disconnect, exception}
to
disconnect
Types
Functions
Specs
child_spec(module, opts :: Keyword.t, child_opts :: Keyword.t) :: Supervisor.Spec.spec
Create a supervisor child specification for a pool of connections.
See Supervisor.Spec
for child options (child_opts
).
Specs
close(conn, query, opts :: Keyword.t) ::
:ok |
{:error, Exception.t}
Close a prepared query on a database connection and return :ok
on
success or {:error, exception}
on error.
This function should be used to free resources held by the connection process and/or the database server.
Options
:queue_timeout
- The time to wait for control of the connection’s state, if the pool allows setting the timeout per request (default:5_000
):queue
- Whether to block waiting in an internal queue for the connection’s state (boolean, default:true
):timeout
- The maximum time that the caller is allowed the to hold the connection’s state (ignored when using a run/transaction connection, default:15_000
)
The pool and connection module may support other options. All options
are passed to handle_close/3
.
See prepare/3
.
Close a prepared query on a database connection and return :ok
.
Raises an exception on error.
See close/3
.
Specs
execute(conn, query, opts :: Keyword.t) ::
{:ok, result} |
{:error, Exception.t}
Execute a prepared query with a database connection and return
{:ok, result}
on success or {:error, exception}
if there was an
error.
Options
:queue_timeout
- The time to wait for control of the connection’s state, if the pool allows setting the timeout per request (default:5_000
):queue
- Whether to block waiting in an internal queue for the connection’s state (boolean, default:true
):timeout
- The maximum time that the caller is allowed the to hold the connection’s state (ignored when using a run/transaction connection, default:15_000
):encode
- Query encode method::auto
uses theDBConnection.Query
protocol to encode any query parameters and:manual
does not (default::auto
):decode
- Result decode method::auto
uses theDBConnection.Result
protocol to decode the query and:manual
does not (default::auto
)
The pool and connection module may support other options. All options
are passed to handle_execute/3
.
See prepare/3
.
Execute a prepared query with a database connection and return the result. Raises an exception on error.
See execute/3
Specs
prepare(conn, query, opts :: Keyword.t) ::
{:ok, query} |
{:error, Exception.t}
Prepare a query with a database connection for later execution and
returns {:ok, query}
on success or {:error, exception}
if there was
an error.
The returned query
can then be passed to execute/3
and/or close/3
Options
:queue_timeout
- The time to wait for control of the connection’s state, the pool allows setting the timeout per request (default:5_000
):queue
- Whether to block waiting in an internal queue for the connection’s state (boolean, default:true
):timeout
- The maximum time that the caller is allowed the to hold the connection’s state (ignored when using a run/transaction connection, default:15_000
):prepare
- Query prepare method::auto
uses theDBConnection.Query
protocol to prepare the query and:manual
does not (default::auto
)
The pool and connection module may support other options. All options
are passed to handle_prepare/3
.
Example
{ok, query} = DBConnection.prepare(pid, "SELECT id FROM table")
{:ok, [_|_]} = DBConnection.execute(pid, query)
:ok = DBConnection.close(pid, query)
Prepare a query with a database connection and return the prepared query. An exception is raised on error.
See prepare/3
.
Specs
query(conn, query, opts :: opts :: Keyword.t) ::
{:ok, result} |
{:error, Exception.t}
Run a query with a database connection and returns {:ok, result}
on
success or {:error, exception}
if there was an error.
Options
:queue_timeout
- The time to wait for control of the connection’s state, if the pool allows setting the timeout per request (default:5_000
):queue
- Whether to block waiting in an internal queue for the connection’s state (boolean, default:true
):timeout
- The maximum time that the caller is allowed the to hold the connection’s state (ignored when using a run/transaction connection, default:15_000
):prepare
- Query prepare method::auto
uses theDBConnection.Query
protocol to prepare the query and:manual
does not (default::auto
):decode
- Result decode method::auto
uses theDBConnection.Result
protocol to decode the query and:manual
does not (default::auto
)
The pool and connection module may support other options. All options
are passed to handle_query/3
.
Example
{:ok, _} = DBConnection.query(pid, "SELECT id FROM table", [decode: :manual])
Run a query with a database connection and return the result. An exception is raised on error.
See query/3
.
Specs
rollback(t, reason :: any) :: no_return
Rollback a transaction, does not return.
Aborts the current transaction fun. If inside transaction/3
bubbles
up to the top level.
Example
{:error, :bar} = DBConnection.transaction(pid, fn(conn) ->
DBConnection.rollback(conn, :bar)
IO.puts "never reaches here!"
end)
Acquire a lock on a connection and run a series of requests on it. The
result of the fun is return inside an :ok
tuple: {:ok result}
.
To use the locked connection call the request with the connection
reference passed as the single argument to the fun
. If the
connection disconnects all future calls using that connection
reference will fail.
run/3
and transaction/3
can be nested multiple times but a
transaction/3
call inside another transaction/3
will be treated
the same as run/3
.
Options
:queue_timeout
- The time to wait for control of the connection’s state, if the pool allows setting the timeout per request (default:5_000
):queue
- Whether to block waiting in an internal queue for the connection’s state (boolean, default:true
):timeout
- The maximum time that the caller is allowed the to hold the connection’s state (default:15_000
)
The pool may support other options.
Example
{:ok, res} = DBConnection.run(pid, fn(conn) ->
res = DBConnection.query!(conn, "SELECT id FROM table")
res
end)
Specs
start_link(module, opts :: Keyword.t) :: GenServer.on_start
Start and link to a database connection process.
Options
:pool_mod
- TheDBConnection.Pool
module to use, (default:DBConnection.Connection
):idle_timeout
- The idle timeout to ping the database (default:15_000
):backoff_start
- The first backoff interval (default:200
):backoff_max
- The maximum backoff interval (default:15_000
):backoff_type
- The backoff strategy,:stop
for no backoff and to stop (see:backoff
, default::jitter
)
Example
{:ok, pid} = DBConnection.start_link(mod, [idle_timeout: 5_000])
Specs
Acquire a lock on a connection and run a series of requests inside a
tranction. The result of the transaction fun is return inside an :ok
tuple: {:ok result}
.
To use the locked connection call the request with the connection
reference passed as the single argument to the fun
. If the
connection disconnects all future calls using that connection
reference will fail.
run/3
and transaction/3
can be nested multiple times but a
transaction/3
call inside another transaction/3
will be treated
the same as run/3
.
Options
:queue_timeout
- The time to wait for control of the connection’s state, if the pool allows setting the timeout per request (default:5_000
):queue
- Whether to block waiting in an internal queue for the connection’s state (boolean, default:true
):timeout
- The maximum time that the caller is allowed the to hold the connection’s state (default:15_000
)
The pool and connection module may support other options. All options
are passed to handle_begin/2
, handle_commit/2
and
handle_rollback/2
.
Example
{:ok, res} = DBConnection.transaction(pid, fn(conn) ->
res = DBConnection.query!(conn, "SELECT id FROM table")
res
end)
Macros
Use DBConnection
to set the behaviour and include default
implementations for handle_prepare/3
(no-op), handle_execute/3
(forwards to handle_query
) and handle_close/3
(no-op) for
connections that don’t handle the prepare/execute/close pattern.
handle_info/2
is also implemented as a no-op.
Callbacks
Specs
checkin(state :: any) ::
{:ok, new_state :: any} |
{:disconnect, Exception.t, new_state :: any}
Checks in the state to the connection process. Return {:ok, state}
to allow the checkin or {:disconnect, exception}
to disconnect.
This callback is called when the control of the state is passed back
to the connection process. It should reverse any changes made in
checkout/2
.
Specs
checkout(state :: any) ::
{:ok, new_state :: any} |
{:disconnect, Exception.t, new_state :: any}
Checkouts the state from the connection process. Return {:ok, state}
to allow the checkout or `{:disconnect, exception} to disconnect.
This callback is called when the control of the state is passed to
another process. checkin/1
is called with the new state when control
is returned to the connection process.
Messages are discarded, instead of being passed to handle_info/2
,
when the state is checked out.
Specs
connect(opts :: Keyword.t) ::
{:ok, state :: any} |
{:error, Exception.t}
Connect to the databases. Return {:ok, state}
on success or
{:error, exception}
on failure.
If an error is returned it will be logged and another connection attempt will be made after a backoff interval.
Specs
disconnect(err :: Exception.t, state :: any) :: :ok
Disconnect from the database. Return :ok
.
The exception as first argument is the exception from a :disconnect
3-tuple returned by a previous callback.
If the state is controlled by a client and it exits or takes too long to process a request the state will be last known state. In these cases the exception will be a `DBConnection.Error.
Specs
handle_begin(opts :: Keyword.t, state :: any) ::
{:ok, new_state :: any} |
{:error | :disconnect, Exception.t, new_state :: any}
Handle the beginning of a transaction. Return {:ok, state}
to
continue, {:error, exception, state}
to abort the transaction and
continue or {:disconnect, exception, state}
to abort the transaction
and disconnect.
Specs
handle_close(query, opts :: Keyword.t, state :: any) ::
{:ok, new_state :: any} |
{:error | :disconnect, Exception.t, new_state :: any}
Close a query prepared by handle_prepare/3
with the database. Return
{:ok, state}
on success and to continue,
{:error, exception, state}
to return an error and continue, or
{:disconnect, exception, state}
to return an error and disconnect.
Specs
handle_commit(opts :: Keyword.t, state :: any) ::
{:ok, new_state :: any} |
{:error | :disconnect, Exception.t, new_state :: any}
Handle commiting a transaction. Return {:ok, state}
on success and
to continue, {:error, exception, state}
to abort the transaction and
continue or {:disconnect, exception, state}
to abort the transaction
and disconnect.
Specs
handle_execute(query, opts :: Keyword.t, state :: any) ::
{:ok, result, new_state :: any} |
{:error | :disconnect, Exception.t, new_state :: any}
Execute a query prepared by handle_prepare/3
. Return
{:ok, result, state}
to return the result result
and continue,
{:error, exception, state}
to return an error and continue or
{:disconnect, exception, state{}
to return an error and disconnect.
Specs
handle_info(msg :: any, state :: any) ::
{:ok, new_state :: any} |
{:disconnect, Exception.t, new_state :: any}
Handle a message received by the connection process when checked in.
Return {:ok, state}
to continue or `{:disconnect, exception,
state}` to disconnect.
Messages received by the connection process when checked out will be logged and discared.
Specs
handle_prepare(query, opts :: Keyword.t, state :: any) ::
{:ok, query, new_state :: any} |
{:error | :disconnect, Exception.t, new_state :: any}
Prepare a query with the database. Return {:ok, query, state}
where
query
is a query to pass to execute/3
or close/3
,
{:error, exception, state}
to return an error and continue or
{:disconnect, exception, state}
to return an error and disconnect.
This callback is intended for cases where the state of a connection is needed to prepare a query and/or the query can be saved in the database to call later.
If the connection is not required to prepare a query, query/3
should be used and the query can be prepared by the
DBConnection.Query
protocol.
Specs
handle_query(query, opts :: Keyword.t, state :: any) ::
{:ok, result, new_state :: any} |
{:error | :disconnect, Exception.t, new_state :: any}
Handle a query. Return {:ok, result, state}
to return the result
result
and to continue, {:error, exception, state}
to return an
error and to continue and {:disconnect, exception, state}
to return
an error and to disconnect.
Specs
handle_rollback(opts :: Keyword.t, state :: any) ::
{:ok, new_state :: any} |
{:error | :disconnect, Exception.t, new_state :: any}
Handle rolling back a transaction. Return {:ok, state}
on success
and to continue, {:error, exception, state}
to abort the transaction
and continue or {:disconnect, exception, state}
to abort the
transaction and disconnect.
A transaction will be rolled back if an exception occurs or
rollback/2
is called.
Specs
ping(state :: any) ::
{:ok, new_state :: any} |
{:disconnect, Exception.t, new_state :: any}
Called when the connection has been idle for a period of time. Return
{:ok, state}
to continue or {:disconnect, exception}
to
disconnect.
This callback is called if no callbacks have been called after the
idle timeout and a client process is not using the state. The idle
timeout can be configured by the :idle_timeout
option. This function
can be called whether the connection is checked in or checked out.