Home

Awesome

Hot Tub

HotTub is a simple, fast, permanent erlang worker pool.

Goals

Primarily I have used this for database workers though other uses are clearly possible. When using this for connection pools the connections themselves should be lazy. Meaning that the process should not fail due to disconnects.

Non-Goals

Implementation

HotTub uses a gen_server process to manage a queue of available workers and of requests for workers. When a worker is available it is dequeued and given away. If there are no workers then the request for a worker is queued. As soon as a worker is returned if a request is queued the worker is given away.

A best effort at avoiding unnecessary work has been done however things could still probably be better.

There is a benchmark as part of the test suite which can be run to give you an idea of the overhead of hottubs worker pool management routines.

Several implementations were tried prior to settling on this one, including an ETS table with N workers using rand() mod n_workers selection, trying to find an available worker from there linearly. This was found to perform faster in some cases, but very poorly in the worst case. See the git history for more information.

Example Usage

demo_worker.erl

-module(demo_worker).

-export([start_link/0]).

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

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

init([]) ->
    {ok, undefined}

handle_call({add, A, B}, _From, State) ->
    {reply, A+B, State}.

handle_cast({print, Message}, State) ->
    io:format("~p~n", [Message]),
    {noreply, State}.

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

terminate(_Reason, State) ->
    ok.

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

erl shell

hottub:start_link(demo, 5, demo_worker, start_link, []).
hottub:call(demo, {add, 5, 5}).
hottub:call(demo, {add, 5, 5}, 1000). %% call with timeout
hottub:cast(demo, {print, "what up from a pool"}).
hottub:execute(demo, 
    fun(Worker) -> 
        io:format("causing a worker to crash~n"),
        gen_server:call(Worker, {hocus_pocus}) end).
hottub:stop(demo).