Skip to content
forked from devinus/poolboy

A hunky Erlang worker pool factory

License

ISC, Unlicense licenses found

Licenses found

ISC
LICENSE
Unlicense
UNLICENSE
Notifications You must be signed in to change notification settings

zugolosian/poolboy

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Poolboy - A hunky Erlang worker pool factory

Build Status

Support via Gratipay

Poolboy is a lightweight, generic pooling library for Erlang with a focus on simplicity, performance, and rock-solid disaster recovery.

Usage

The most basic use case is to check out a worker, make a call and manually return it to the pool when done

1> Worker = poolboy:checkout(PoolName).
<0.9001.0>
2> gen_server:call(Worker, Request).
ok
3> poolboy:checkin(PoolName, Worker).
ok

Alternatively you can use a transaction which will return the worker to the pool when the call is finished.

poolboy:transaction(
    PoolName,
    fun(Worker) -> gen_server:call(Worker, Request) end, 
    TransactionTimeout
)

Example

This is an example application showcasing database connection pools using Poolboy and epgsql.

example.app

{application, example, [
    {description, "An example application"},
    {vsn, "0.1"},
    {applications, [kernel, stdlib, sasl, crypto, ssl]},
    {modules, [example, example_worker]},
    {registered, [example]},
    {mod, {example, []}},
    {env, [
        {pools, [
            {pool1, [
                {size, 10},
                {max_overflow, 20}
			], [
                {hostname, "127.0.0.1"},
                {database, "db1"},
                {username, "db1"},
                {password, "abc123"}
            ]},
            {pool2, [
                {size, 5},
                {max_overflow, 10}
			], [
                {hostname, "127.0.0.1"},
                {database, "db2"},
                {username, "db2"},
                {password, "abc123"}
            ]}
        ]}
    ]}
]}.

example.erl

-module(example).
-behaviour(application).
-behaviour(supervisor).

-export([start/0, stop/0, squery/2, equery/3]).
-export([start/2, stop/1]).
-export([init/1]).

start() ->
    application:start(?MODULE).

stop() ->
    application:stop(?MODULE).

start(_Type, _Args) ->
    supervisor:start_link({local, example_sup}, ?MODULE, []).

stop(_State) ->
    ok.

init([]) ->
    {ok, Pools} = application:get_env(example, pools),
    PoolSpecs = lists:map(fun({Name, SizeArgs, WorkerArgs}) ->
        PoolArgs = [{name, {local, Name}},
            		{worker_module, example_worker}] ++ SizeArgs,
        poolboy:child_spec(Name, PoolArgs, WorkerArgs)
    end, Pools),
    {ok, {{one_for_one, 10, 10}, PoolSpecs}}.

squery(PoolName, Sql) ->
    poolboy:transaction(PoolName, fun(Worker) ->
        gen_server:call(Worker, {squery, Sql})
    end).

equery(PoolName, Stmt, Params) ->
    poolboy:transaction(PoolName, fun(Worker) ->
        gen_server:call(Worker, {equery, Stmt, Params})
    end).

example_worker.erl

-module(example_worker).
-behaviour(gen_server).
-behaviour(poolboy_worker).

-export([start_link/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
         code_change/3]).

-record(state, {conn}).

start_link(Args) ->
    gen_server:start_link(?MODULE, Args, []).

init(Args) ->
    process_flag(trap_exit, true),
    Hostname = proplists:get_value(hostname, Args),
    Database = proplists:get_value(database, Args),
    Username = proplists:get_value(username, Args),
    Password = proplists:get_value(password, Args),
    {ok, Conn} = epgsql:connect(Hostname, Username, Password, [
        {database, Database}
    ]),
    {ok, #state{conn=Conn}}.

handle_call({squery, Sql}, _From, #state{conn=Conn}=State) ->
    {reply, epgsql:squery(Conn, Sql), State};
handle_call({equery, Stmt, Params}, _From, #state{conn=Conn}=State) ->
    {reply, epgsql:equery(Conn, Stmt, Params), State};
handle_call(_Request, _From, State) ->
    {reply, ok, State}.

handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, #state{conn=Conn}) ->
    ok = epgsql:close(Conn),
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

Pool Options

  • name: the pool name - optional
  • worker_module: the module that represents the workers - mandatory
  • size: maximum pool size - optional
  • max_overflow: maximum number of workers created if pool is empty - optional
  • strategy: lifo or fifo, determines whether checked in workers should be placed first or last in the line of available workers. Default is lifo.
  • overflow_ttl: time in milliseconds you want to wait before removing overflow workers. Useful when it's expensive to start workers. Default is 0.

Pool Status

Returns : {Status, Workers, Overflow, InUse}

  • Status: ready | full | overflow The ready atom indicates there are workers that are not checked out ready. The full atom indicates all workers including overflow are checked out. The overflow atom is used to describe the condition when all permanent workers are in use but there is overflow capacity available.
  • Workers: Number of workers ready for use.
  • Overflow: Number of overflow workers started, should never exceed number specified by MaxOverflow when starting pool
  • InUse: Number of workers currently busy/checked out

Full Pool Status

Returns a propslist of counters relating to a specified pool. Useful for graphing the state of your pools

  • size: The defined size of the permanent worker pool
  • max_overflow: The maximum number of overflow workers allowed
  • total_worker_count: The total supervised workers. This includes any workers waiting to be culled and not available to the general pool
  • ready_worker_count: The count of workers available workers to be used including overflow workers. Workers in this count may or may not be checked out.
  • checked_out_worker_count: The count of workers that are currently checked out
  • overflow_worker_count: The count of active overflow workers
  • waiting_request_count: The backlog of requests waiting to checkout a worker

Authors

License

Poolboy is available in the public domain (see UNLICENSE). Poolboy is also optionally available under the ISC license (see LICENSE), meant especially for jurisdictions that do not recognize public domain works.

About

A hunky Erlang worker pool factory

Resources

License

ISC, Unlicense licenses found

Licenses found

ISC
LICENSE
Unlicense
UNLICENSE

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Erlang 99.5%
  • Makefile 0.5%