puddle
A resource pool manager for Gleam. Manages a fixed pool of reusable resources with automatic crash recovery and backpressure.
Installation
gleam add puddle
Quick Start
Basic usage
import gleam/int
import gleam/io
import puddle
pub fn main() {
let assert Ok(manager) =
puddle.new(fn() { Ok(int.random(8192)) })
|> puddle.size(4)
|> puddle.start(1000)
let result = {
use r <- puddle.apply(manager, fn(n) { puddle.keep(n * 2) }, 1000)
r
}
io.debug(result)
puddle.shutdown(manager)
}
Resource discard
When a resource becomes invalid, signal the pool to destroy it and create a replacement:
let result = {
use r <- puddle.apply(manager, fn(conn) {
case db.query(conn, "SELECT 1") {
Ok(rows) -> puddle.keep(rows)
Error(_) -> puddle.discard([])
}
}, 1000)
r
}
Blocking checkout
When all resources are busy, apply_blocking queues the request instead of returning an error:
let result = {
use r <- puddle.apply_blocking(manager, fn(n) { puddle.keep(n) }, 5000)
r
}
Named pools
Give a pool a name to access it globally without passing the manager reference:
import gleam/erlang/process
let pool_name = process.new_name("my_db_pool")
let assert Ok(manager) =
puddle.new(create_connection)
|> puddle.size(10)
|> puddle.name(pool_name)
|> puddle.start(5000)
// Access from anywhere using the name
let named = process.named_subject(pool_name)
let result = {
use r <- puddle.apply(named, fn(conn) { puddle.keep(conn) }, 1000)
r
}
Configuration options
let assert Ok(manager) =
puddle.new(create_connection)
|> puddle.size(10)
|> puddle.checkout_strategy(puddle.LIFO)
|> puddle.creation_strategy(puddle.Lazy)
|> puddle.on_shutdown(fn(conn) { db.close(conn) })
|> puddle.start(5000)
Pool size
puddle.size(n) — maximum number of resources in the pool (default: 10).
Checkout strategy
puddle.checkout_strategy(strategy) — how idle resources are selected:
puddle.FIFO(default) — oldest idle resource first, fair orderingpuddle.LIFO— most recently returned resource first, better cache locality
Creation strategy
puddle.creation_strategy(strategy) — when resources are created:
puddle.Eager(default) — create all resources at startuppuddle.Lazy— create resources on first demand, up tosize
Shutdown callback
puddle.on_shutdown(fn(resource) { ... }) — called for each resource when the pool shuts down.
Pool name
puddle.name(process.new_name("my_pool")) — register the pool under a globally accessible name.
Pool status
let status = puddle.status(manager, 1000)
// status.state: Ready | Full | Overloaded
// status.size, status.available, status.busy, status.waiting
Pool states:
Ready— idle resources availableFull— all resources busy, no waitersOverloaded— all resources busy, requests queued
OTP supervision
import gleam/otp/static_supervisor
let child_spec =
puddle.new(create_resource)
|> puddle.size(5)
|> puddle.supervised(5000)
let assert Ok(_supervisor) =
static_supervisor.new(static_supervisor.OneForOne)
|> static_supervisor.add(child_spec)
|> static_supervisor.start
Named supervised pools
Combine name with supervised for globally accessible supervised pools:
let pool_name = process.new_name("my_pool")
let child_spec =
puddle.new(create_resource)
|> puddle.size(5)
|> puddle.name(pool_name)
|> puddle.supervised(5000)
// Start under supervisor, then access anywhere via:
let manager = process.named_subject(pool_name)