phasync
Resource management / Pool

Class

Pool

A pool of interchangeable resources, of which only so many may exist at once.

Introduction#

For database connections, sockets to a service, workers. A coroutine borrows one, uses it alone, and releases it; while all are out, the next borrower waits for one.

Class synopsis#

final class Pool implements \Countable {
    /* Methods */
    public Pool::__construct(
        Closure $create,
        int $size,
        ?float $window = null,
        ?Closure $dispose = null
    )
    public Pool::borrow(float $timeout = PHP_FLOAT_MAX): object
    public Pool::release(object $instance): void
    public Pool::discard(object $instance): void
    public Pool::use(Closure $fn, float $timeout = PHP_FLOAT_MAX): mixed
    public Pool::count(): int
}

Methods#

MethodDescription
__constructCreates an empty pool; instances are made when they are needed.
borrowLends an instance to the caller until it calls release() or discard(), and waits while all are out.
releaseGives a borrowed instance back, for the next borrower.
discardGives a borrowed instance back as broken: the pool forgets it, passes it to $dispose, and makes a new one when needed.
useRuns $fn with an instance of its own, and releases the instance afterwards, also when $fn throws.
countReturns the number of instances in existence: lent out, being made, and idle.

Examples#

Example 1
$db = new phasync\Util\Pool(fn () => new PDO($dsn, $user, $password), 10);

// Heavy instances: give memory back 30 s after a burst, and flush what is dropped
$apps = new phasync\Util\Pool(fn () => bootApplication(), 8, window: 30, dispose: fn ($app) => $app->flush());

$rows = $db->use(fn (PDO $pdo) => $pdo->query('SELECT ...')->fetchAll());

$pdo = $db->borrow();          // or by hand
try {
    // ...
} finally {
    $db->release($pdo);
}

See also#

  • SynchronizedA mutex for coroutines, identified by a string or an object: only one coroutine at a time runs a closure for the same token.
  • RateLimiterLets events pass at a fixed rate, shared by every coroutine that calls wait().

Used in#

  • LaravelRun a Laravel application on Swerve: many requests at once, each in a pooled application of its own.
  • Making your application safe for concurrent requestsAn adapter running your framework correctly under Swerve doesn't make your own code safe for requests that overlap. The checklist, with a fix for each item.
  • Connections, pools and limitsA worker needs few database connections. Borrow one for a query or a transaction and give it back.