README.md

# 🙅‍♂️ PoolLad

`pool_lad` is the younger & more energetic version of [`:poolboy`](https://github.com/devinus/poolboy).

It's still the _**lightweight, generic pooling library with focus on
simplicity, performance, and rock-solid disaster recovery**_ that we all love...

...but it has just gotten a much needed facelift!

## Table of contents

-   [Installation](#installation)
-   [Documentation](#documentation)
-   [Sample usage](#sample-usage)

## Installation

Add `:pool_lad` as a dependency to your project's `mix.exs`:

```elixir
defp deps do
  [
    {:pool_lad, "~> 0.0.1"}
  ]
end
```

## Documentation

The full documentation is [published on hex](https://hexdocs.pm/pool_lad/).

## Sample usage

The APIs are almost identical to those of [`:poolboy`](https://github.com/devinus/poolboy).

Via manual ownership:

```elixir
iex(1)> {:ok, pid} = PoolLad.borrow(MyWorkerPool)
{:ok, #PID<0.229.0>}
iex(2)> GenServer.call(pid, :get_latest_count)
{:ok, 42}
iex(3)> PoolLad.return(MyWorkerPool, pid)
:ok
```

Via transactional ownership:

```elixir
iex(1)> PoolLad.transaction(
  MyWorkerPool,
  fn pid -> GenServer.call(pid, :get_latest_count) end
)
{:ok, 42}
```

## Why PoolLad over poolboy

- Elixir-first
- Modern APIs, e.g. `DynamicSupervisor`
- Less code, less pesky logs, less noise
- More documentation
- Same performance
- Maintained

## TODO

- [ ] Add overflow functionality
- [ ] Clean up the below docs

### 1. Define a worker

This would ideally be a `GenServer`, but can be any module that implements `child_spec/1`.

    defmodule MyWorker do
      use GenServer

      @this_module __MODULE__

      def start_link(opts) do
        initial_count = Keyword.get(opts, :initial_count, 0)
        GenServer.start_link(@this_module, initial_count)
      end

      @impl true
      def init(initial_count), do: {:ok, initial_count}

      @impl true
      def handle_call(:get_latest_count, _from, count), do: {reply, count, count}
    end

ℹ️ Please note that workers should not be "named" as multiple instances of the same
worker will be started by the `PoolLad`'s dedicated `DynamicSupervisor`.

### 2. Start the pool

You'd usually start your worker pool as a child under a `Supervisor`.

    pool_opts = [name: MyWorkerPool, worker_count: 3, worker_module: MyWorker]
    worker_opts = [initial_count: 42]

    children = [
      {PoolLad, {pool_opts, worker_opts}}
    ]

    Supervisor.start_link(children, strategy: :one_for_one)

### 3. Do the work

    iex> PoolLad.transaction(
      MyWorkerPool,
      fn pid -> GenServer.call(pid, :get_latest_count) end
    )
    {:ok, 42}

Once you're ready to use the worker, make sure you claim its ownership.

    {:ok, pid} = PoolLad.borrow(MyWorkerPool)

### 4. Do the work

Now that you've claimed unique ownership of the pid, you can use it to perform
the work you need.

    iex> GenServer.call(pid, :get_latest_count)
    {:ok, 42}

### 5. Return the worker

the pid back to the pool so other processes can borrow it it

    :ok = PoolLad.return(MyWorkerPool, pid)

### Simplify

ℹ️ You can make this a little easier by using `transaction/3`.

    iex> PoolLad.transaction(
      MyWorkerPool,
      fn pid -> GenServer.call(pid, :get_latest_count) end
    )
    {:ok, 42}