wrapper application around poolboy to easily spawn worker pools
Erlang
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
include
src
test
.gitignore
README.md
rebar.config

README.md

Waterpark

An erlang application that is mostly for:

  • Having an applicatin for supervising poolboy pools instead of doing it manually for each app.
  • Simplifying working with eredis and epgsql
  • Utility functions

Working with pools

Pools are defined in the pools parameter for waterpark's application environment

spec'ish definition:

{pools,[PoolSpec]}
PoolSpec :: {PoolName,PoolWorker,PoolArgs}
PoolName :: atom(),
PoolWorker :: module(), %implementing poolboy_worker behaviour
PoolArgs = proplist()

The PoolArgs proplist must/can contain any poolboy properties to be set for the worker except for worker_module and name.

Sample app.config entry:

{waterpark,[
             {pools,[
                     {pgsql_pool,wp_pgsql_worker,[
                                        {size,1},
                                        {max_overflow,10},
                                        {host,"127.0.0.1"},
                                        {username,"testuser"},
                                        {password,"testpassword"},
                                        {opts,[{database,"testdb"}]}
                                       ]},
                     {eredis_pool,wp_redis_worker,[
                                          {size,10},
                                          {max_overflow,10}
                                         ]}
                    ]}
            ]}

Working with eredis and epgsql

The main purpose of these helper modules is to make it easier to work with transactions. When a tx is initiated, the calling process gains ownership of the connection. If the owner dies, the connection rolls back. Other processes will get a {error,ownership} if they try to use any functions that participate in transactions.

As the connection owner you are responsible for returning the connection back to the pool in a useable, non-transactional state. This will happen if:

  • you die.
  • you use the tx/? helper functions.
  • you commit/rollback before returning the connection to the pool.

wp_pg module

sq/2					% simple query
eq/2					% extended query
eq/3					% extended query with args
start_tx/1				% start a transaction
commit/1				% commit a transaction
rollback/1				% rollback a transaction
clear/1					% clear connection state
info/1					% see state info ie. tx owner if any
extract_reason/2		% used to extract errors from wp_pg:error()s
tx/2                    % executes a function within a transaction
  • All calls except info/1 and extract_reason/2 can throw wp_pg:error().
  • Unlike regular epgsql query functions, if the query returns an error it is thrown as a wp_pg:error() which is a 3-tuple with a reason and a message. The reason is an attempted translation of the database error.
  • start_tx/1 begins a transaction and gives ownership to calling process.
  • a start_tx/1 call must have an equivalent commit/1 call.
  • start_tx/1 can be called multiple times. Each call must have an equivalent commit/1. Note this does not do anything to the underlying database, it just makes it easier to call transactions within transcations. Savepoints are not supported.
  • rollback/1 will reset the connection. clear/1 does the same thing but it ignores ownership, so anyone can call it.

tx(Conn,Fun) is a wrapper among the primitive tx control functions, essentialy it will execute Fun within a transaction and take care of start,commiting and cleaning up for you. If a serialization error occurs it will retry it until it succeedes. If any errors occur within the function the tx is rolled back and the errors rethrown. This function guarantees consistent connection state upon returning. does not support nested calls right now. This function should mostly be used to interact with the database. Only execute queries from within Fun, calling any of the transaction related functions will/may screw things up.

Conn = poolboy:checkout(pgsql_pool),
% below executed transactionaly
{ok,we_win} = wp_pg:tx(Conn,fun(C) ->
                              wp_pg:eq(Conn,"SELECT ...",[...Args...]),
							  wp_pg:eq(Conn,"UPDATE ...",[...Args...]),
						      wp_pg:eq(Conn,"DELETE ...",[...Args...]),
							  {ok,we_win}
              end),
% no changes to db
{error,we_fail} = catch(wp_pg:tx(Conn,fun(C) ->
	                                    wp_pg:eq(Conn,"SELECT ...",[...Args...]),
										wp_pg:eq(Conn,"UPDATE ...",[...Args...]),
										wp_pg:eq(Conn,"DELETE ...",[...Args...]),
										throw({error,we_fail})
                                      end)).

WIP