std/task/pool
std/task/src/pool.trb
A pool of resources, written once over Permits: at most maximum of them open at once, the idle ones kept for the
next Pool.acquire, and a caller beyond maximum waits, oldest first.
const pool = Pool.of(4, { connect(address) })
using lease = pool.acquire().await()?
lease.resource.send(request).await()?
lease.giveBack()
Reach for it wherever opening a resource is dear and holding too many is harmful: connections to a server, handles of
a device, processes of a helper. What the pool does not know stays with the caller: a key per origin (keep one Pool
for each), a timeout (pool.acquire().within(limit), as Permits.acquire is a task), and what happens to a resource
while it is lent out.
Pitfalls
- A
Leasehas to be settled, once:Lease.giveBackwhere the resource is still good,Lease.discardwhere it is not. A lease that is released without either discards its resource, so bind it withusingand a failure or a cancellation gives the slot back too. reusableruns insidePool.acquire, once for every idle resource looked at: keep it cheap, and do not let it wait. A resource it refuses is dropped.- A resource is dropped, not closed by the pool; give it a
close()where it holds something that must be given back.
type PoolError
type PoolError<Failure>
Why Pool.acquire gave no resource: the pool was stopped, or opening a new one failed with failure.
extend PoolError<Failure> with Show
extend<Failure: Show> PoolError<Failure> with Show
The error in words: the pool is closed, or could not open a resource: and the failure.
fn show
fn show(): String
type Pool
shared type Pool<Resource, Failure>
A pool of at most maximum resources. See the module comment for when to use it; the pool is shared, so every holder
of it sees the same slots.
field maximum
maximum: Int
How many resources may be open at once: what it was made with, taken as 1 where that was below 1.
fn of
static fn of(maximum: Int, open: () => Task<Result<Resource, Failure>>, reusable: (resource: Resource) => Bool = { _ => true }): Self
A pool of maximum resources, opened by open when an Pool.acquire finds no idle one. reusable tells whether an
idle resource may be lent again; it answers true for every resource unless the pool is made with another. A
maximum below 1 is taken as 1.
fn acquire
var fn acquire(): Task<Result<Lease<Resource>, PoolError<Failure>>>
Waits for a free slot, then lends the newest idle resource that is reusable - the others found on the way are
dropped - or opens a new one. A failed open gives the slot back and answers PoolError.Open; a pool that is
stopped answers PoolError.Closed, also where it was stopped while the caller waited. A caller cancelled while it
waits takes no slot.
fn stop
var fn stop()
Drops the idle resources; what is returned later is dropped, and every later Pool.acquire answers Closed.
fn close
var fn close()
What the release of the pool runs: the same as Pool.stop.
fn idleCount
fn idleCount(): Int
How many resources are idle now.
fn openCount
fn openCount(): Int
How many resources are open now: the idle ones and those that are lent out.
type Lease
shared type Lease<Resource> with Close
One caller's hold on a slot and on the resource in it. It is settled exactly once, however often it is asked: given
back to the pool by Lease.giveBack, or dropped by Lease.discard - and the release of the lease discards where
neither ran, so a caller that fails or is cancelled gives its slot back.
field resource
resource: Resource
The resource that is lent.
fn giveBack
var fn giveBack()
The resource is good: kept for the next caller where the pool is running and reusable agrees; the slot is free.
fn discard
var fn discard()
The resource is dropped, and the slot is free.
fn close
var fn close()
Discards what neither Lease.giveBack nor Lease.discard settled: what the release of the lease runs.