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.
- Instances are made by
$createwhen one is needed and none is free, up to$size; they are reused after that. - Borrowers waiting are served in the order they came: a released instance goes to the one that waited longest.
- An instance that broke (a lost database connection) is given back with
discard()instead: the pool forgets it, and makes a new one when needed. - An instance dropped by its borrower without
release()ordiscard()is noticed when it is destroyed: the pool warns (E_USER_WARNING) and makes a new one in its place. A borrower waiting meanwhile finds out within a second. - With
$window, the pool shrinks to the most instances that were lent at once within the last$windowseconds: an idle instance is dropped only while more instances exist than that. A burst keeps its instances for$windowseconds, then they go. This is checked whenborrow()orrelease()is called, never by a timer, so memory is returned the next time the pool is used, not when the window ends. - With
$dispose, an instance the pool lets go of (dropped as idle, or given back withdiscard()) is passed to it, to close or flush it.$disposemust cope with an instance that is already closed or broken, and an exception from it propagates like any coroutine's. It is not called for an instance lost without being given back, which is already destroyed.
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#
| Method | Description |
|---|---|
__construct | Creates an empty pool; instances are made when they are needed. |
borrow | Lends an instance to the caller until it calls release() or discard(), and waits while all are out. |
release | Gives a borrowed instance back, for the next borrower. |
discard | Gives a borrowed instance back as broken: the pool forgets it, passes it to $dispose, and makes a new one when needed. |
use | Runs $fn with an instance of its own, and releases the instance afterwards, also when $fn throws. |
count | Returns the number of instances in existence: lent out, being made, and idle. |
Examples#
$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 callswait().
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.