Skip to content

Commit

Permalink
Separate pool args and worker args into two lists
Browse files Browse the repository at this point in the history
  • Loading branch information
Devin Torres committed Aug 10, 2012
1 parent 985f6cf commit ce08748
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 43 deletions.
35 changes: 16 additions & 19 deletions README.md
@@ -1,10 +1,8 @@
Poolboy - A hunky Erlang worker pool factory
============================================
# Poolboy - A hunky Erlang worker pool factory

[![Build Status](https://secure.travis-ci.org/devinus/poolboy.png?branch=master)](http://travis-ci.org/devinus/poolboy)

Usage
-----
## Usage

```erl-sh
1> Worker = poolboy:checkout(PoolName).
Expand All @@ -15,8 +13,7 @@ ok
ok
```

Example
-------
## Example

This is an example application showcasing database connection pools using
Poolboy and Will Glozer's [epgsql](https://github.com/wg/epgsql).
Expand All @@ -35,15 +32,17 @@ Poolboy and Will Glozer's [epgsql](https://github.com/wg/epgsql).
{pools, [
{pool1, [
{size, 10},
{max_overflow, 20},
{max_overflow, 20}
], [
{hostname, "127.0.0.1"},
{database, "db1"},
{username, "db1"},
{password, "abc123"}
]},
{pool2, [
{size, 5},
{max_overflow, 10},
{max_overflow, 10}
], [
{hostname, "127.0.0.1"},
{database, "db2"},
{username, "db2"},
Expand Down Expand Up @@ -79,11 +78,10 @@ stop(_State) ->

init([]) ->
{ok, Pools} = application:get_env(example, pools),
PoolSpecs = lists:map(fun({PoolName, PoolConfig}) ->
Args = [{name, {local, PoolName}},
{worker_module, example_worker}]
++ PoolConfig,
poolboy:child_spec(PoolName, Args)
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}}.

Expand Down Expand Up @@ -145,22 +143,21 @@ code_change(_OldVsn, State, _Extra) ->
{ok, State}.
```

Options
-------
## Options

- `name`: the pool name
- `worker_module`: the module that represents the workers
- `size`: maximum pool size
- `max_overflow`: maximum number of workers created if pool is empty

Authors
-------
## Authors

- Devin Torres (devinus) <devin@devintorres.com>
- Andrew Thompson (Vagabond) <andrew@hijacked.us>
- Kurt Williams (onkel-dirtus) <kurt.r.williams@gmail.com>

License
-------
## License

Poolboy is available in the public domain (see `UNLICENSE`).
Poolboy is also optionally available under the Apache License (see `LICENSE`),
meant especially for jurisdictions that do not recognize public domain works.
63 changes: 39 additions & 24 deletions src/poolboy.erl
Expand Up @@ -4,7 +4,8 @@
-behaviour(gen_fsm).

-export([checkout/1, checkout/2, checkout/3, checkin/2, transaction/2,
child_spec/2, start_link/1, stop/1, status/1]).
child_spec/2, child_spec/3, start_link/1, start_link/2, stop/1,
status/1]).
-export([init/1, ready/2, ready/3, overflow/2, overflow/3, full/2, full/3,
handle_event/3, handle_sync_event/4, handle_info/3, terminate/3,
code_change/4]).
Expand Down Expand Up @@ -48,45 +49,59 @@ transaction(Pool, Fun) ->
ok = poolboy:checkin(Pool, Worker)
end.

-spec child_spec(Pool :: node(), Args :: proplists:proplist()) ->
supervisor:child_spec().
child_spec(Pool, Args) ->
{Pool, {poolboy, start_link, [Args]},
-spec child_spec(Pool :: node(), PoolArgs :: proplists:proplist())
-> supervisor:child_spec().
child_spec(Pool, PoolArgs) ->
child_spec(Pool, PoolArgs, []).

This comment has been minimized.

Copy link
@Vagabond

Vagabond Sep 4, 2012

Wouldn't it be more backwards compatible to pass PoolArgs as the WorkerArgs parameter here, so all the old usage of this API still works?


-spec child_spec(Pool :: node(),
PoolArgs :: proplists:proplist(),
WorkerArgs :: proplists:proplist())
-> supervisor:child_spec().
child_spec(Pool, PoolArgs, WorkerArgs) ->
{Pool, {poolboy, start_link, [PoolArgs, WorkerArgs]},
permanent, 5000, worker, [poolboy]}.

-spec start_link(Args :: proplists:proplist()) -> {ok, pid()}.
start_link(Args) ->
case proplists:get_value(name, Args) of
-spec start_link(PoolArgs :: proplists:proplist())
-> {ok, pid()}.
start_link(PoolArgs) ->
start_link(PoolArgs, []).

This comment has been minimized.

Copy link
@Vagabond

Vagabond Sep 4, 2012

Actually, backwards compat would make more sense here.


-spec start_link(PoolArgs :: proplists:proplist(),
WorkerArgs:: proplists:proplist())
-> {ok, pid()}.
start_link(PoolArgs, WorkerArgs) ->
case proplists:get_value(name, PoolArgs) of
undefined ->
gen_fsm:start_link(?MODULE, Args, []);
gen_fsm:start_link(?MODULE, {PoolArgs, WorkerArgs}, []);
Name ->
gen_fsm:start_link(Name, ?MODULE, Args, [])
gen_fsm:start_link(Name, ?MODULE, {PoolArgs, WorkerArgs}, [])
end.

-spec stop(Pool :: node()) -> ok.
stop(Pool) ->
gen_fsm:sync_send_all_state_event(Pool, stop).

-spec status(Pool :: node()) -> {state, integer(), integer(), integer()}.
-spec status(Pool :: node()) -> {atom(), integer(), integer(), integer()}.
status(Pool) ->
gen_fsm:sync_send_all_state_event(Pool, status).

init(Args) ->
init({PoolArgs, WorkerArgs}) ->
process_flag(trap_exit, true),
Waiting = queue:new(),
Monitors = ets:new(monitors, [private]),
init(Args, Args, #state{waiting=Waiting, monitors=Monitors}).

init([{worker_module, Mod} | Rest], Args, State) when is_atom(Mod) ->
{ok, Sup} = poolboy_sup:start_link(Mod, Args),
init(Rest, Args, State#state{supervisor=Sup});
init([{size, Size} | Rest], Args, State) when is_integer(Size) ->
init(Rest, Args, State#state{size=Size});
init([{max_overflow, MaxOverflow} | Rest], Args, State) when is_integer(MaxOverflow) ->
init(Rest, Args, State#state{max_overflow=MaxOverflow});
init([_ | Rest], Args, State) ->
init(Rest, Args, State);
init([], _Args, #state{size=Size, supervisor=Sup, max_overflow=MaxOverflow}=State) ->
init(PoolArgs, WorkerArgs, #state{waiting=Waiting, monitors=Monitors}).

init([{worker_module, Mod} | Rest], WorkerArgs, State) when is_atom(Mod) ->
{ok, Sup} = poolboy_sup:start_link(Mod, WorkerArgs),
init(Rest, WorkerArgs, State#state{supervisor=Sup});
init([{size, Size} | Rest], WorkerArgs, State) when is_integer(Size) ->
init(Rest, WorkerArgs, State#state{size=Size});
init([{max_overflow, MaxOverflow} | Rest], WorkerArgs, State) when is_integer(MaxOverflow) ->
init(Rest, WorkerArgs, State#state{max_overflow=MaxOverflow});
init([_ | Rest], WorkerArgs, State) ->
init(Rest, WorkerArgs, State);
init([], _WorkerArgs, #state{size=Size, supervisor=Sup, max_overflow=MaxOverflow}=State) ->
Workers = prepopulate(Size, Sup),
StartState = case Size of
Size when Size < 1, MaxOverflow < 1 -> full;
Expand Down

0 comments on commit ce08748

Please sign in to comment.