puddle
Types
A resource pool manager for Gleam.
puddle manages a fixed-size pool of reusable resources (workers), each holding
a single resource instance. It handles check-out/check-in, automatic crash recovery,
and backpressure when the pool is exhausted.
Quick Start
import gleam/int
import gleam/io
import puddle
pub fn main() {
let assert Ok(manager) = puddle.start(4, fn() { Ok(int.random(8192)) }, 1000)
let result = {
use r <- puddle.apply(manager, fn(n) { n * 2 }, 1000)
r
}
io.debug(result) // Ok(16384)
}
Resource Lifecycle
- Creation:
startspawnssizeworkers, each callingcreate_resource - Check-out:
applyacquires an idle worker exclusively - Execution: User function runs with the resource
- Check-in: Resource returned to idle pool automatically (via
usesyntax) - Shutdown:
shutdowngracefully stops all workers
Crash Recovery
- Idle worker crash: Replaced automatically, pool size maintained
- Busy worker crash: Replaced automatically; caller receives
Error(Nil) - User process crash: Resource returned to pool automatically
Concurrency
- Multiple processes can call
applyconcurrently - Same process can reuse the pool sequentially
- Pool exhaustion returns
Error(Nil)immediately (no queueing)
See puddle_test.gleam for usage patterns and edge cases.
pub opaque type ManagerMessage(resource_type, result_type)
pub opaque type ResourceMessage(resource_type, result_type)
Values
pub fn apply(
manager: process.Subject(
ManagerMessage(resource_type, result_type),
),
fun: fn(resource_type) -> result_type,
timeout: Int,
rest: fn(Result(result_type, Nil)) -> Result(a, Nil),
) -> Result(a, Nil)
Checks out a resource, applies fun, and checks the resource back in.
Uses Gleam’s use syntax for automatic check-in. The resource is returned to
the idle pool when the use block exits (normally or via error).
Parameters
manager: Pool manager returned bystartfun: Function receiving the resource, returning a resulttimeout: Milliseconds to wait for check-out AND function execution
Returns
Result(result_type, Nil) via continuation. Returns Error(Nil) if:
- No idle workers available (pool exhausted)
- Check-out times out
- Function execution times out
- Worker crashes during execution
Example
let result = {
use conn <- puddle.apply(pool, fn(c) { query(c, "SELECT * FROM users") }, 2000)
conn
}
// result = Ok("...") or Error(Nil)
pub fn shutdown(
manager: process.Subject(
ManagerMessage(resource_type, result_type),
),
shutdown_resource: fn(resource_type) -> Nil,
) -> Nil
Gracefully shuts down the pool.
Sends a shutdown signal to the manager. The manager will:
- Immediately shut down all idle workers (calling
shutdown_resource) - Wait for busy workers to complete their current
apply, then shut them down - Stop the manager actor
Parameters
manager: Pool manager fromstartshutdown_resource: Function to clean up a resource (e.g., close connection)
Example
puddle.shutdown(pool, fn(DbConnection(host, port)) {
close_connection(host, port)
})
pub fn start(
size: Int,
create_resource: fn() -> Result(resource_type, Nil),
timeout: Int,
) -> Result(
process.Subject(ManagerMessage(resource_type, result_type)),
actor.StartError,
)
Starts a new resource pool with the given size.
Each worker is initialized by calling create_resource. If any worker fails to
initialize, the entire pool startup fails and returns Error(actor.StartError).
Parameters
size: Number of workers in the pool (fixed for the pool’s lifetime)create_resource: Function that creates a resource instance. ReturnOk(resource)on success,Error(Nil)on failure.timeout: Milliseconds to wait for pool initialization.
Returns
Ok(manager_subject) on success, Error(actor.StartError) on failure.
Example
let assert Ok(pool) = puddle.start(10, fn() { connect_to_db() }, 5000)