API reference
Six types, all in the Flytachi\Winter\CPool namespace. Signatures match the
source; for each item you get the arguments, the return value and any non-obvious
semantics.
Overview
| Type | Kind | Role |
|---|---|---|
ConnectionFactory |
interface | the driver adapter — the single extension point |
ConnectionPool |
class | the pool: borrow, release, evict |
SingleConnection |
class | the same meaning for a runtime without concurrency |
PoolEntry |
DTO | a borrowed connection and its timestamps |
PoolPolicy |
value | the settings |
PoolException |
exception | the package’s only exception |
ConnectionFactory (interface)
public function create(): object;
public function validate(object $connection): bool;
public function close(object $connection): void;| Method | Description |
|---|---|
create() |
Open a connection. May throw — the pool wraps it in PoolException::connectFailed() |
validate($c) |
A cheap liveness probe. false → the pool evicts and opens a new one. A thrown exception counts as death too |
close($c) |
Close it. The pool ignores errors |
In detail — in Writing an adapter.
ConnectionPool (final class)
new ConnectionPool(
ConnectionFactory $factory,
PoolPolicy $policy = new PoolPolicy(),
?Closure $clock = null,
)$clock substitutes the time source, for tests; production code does not need it.
| Method | Returns | Description |
|---|---|---|
borrow() |
PoolEntry |
Take a live connection. Below the cap it creates one; at the cap it waits. Dead and expired ones are discarded and the next is tried, until connectionTimeout — the deadline for the whole borrow — runs out. Throws exhausted() (all busy), connectFailed() (could not open), unusable() (the window went on dead connections) |
release($entry) |
void |
Return it to the pool. The timestamp is refreshed, the probe is not run |
evict($entry) |
void |
Evict and close — for when the caller knows the connection is broken |
stats() |
array |
['total', 'idle', 'active', 'maximum'] |
close() |
void |
Close every connection and disarm the housekeeping timer |
abandon() |
void |
Forget every connection without closing and disarm the timer — the fork-safe counterpart of close() |
Releasing is mandatory
The pool does not track connections that were never returned: every leak permanently
shrinks it by one. Wrap borrow() in try/finally, or build a facade that releases at
the end of the unit of work.
evict() versus release()
release() puts the connection back into circulation as is. If you know it is broken
— the driver reported a disconnect — returning it means handing a corpse to the next
borrower. That is what evict() is for.
SingleConnection (final class)
new SingleConnection(
ConnectionFactory $factory,
PoolPolicy $policy = new PoolPolicy(),
?Closure $clock = null,
)| Method | Returns | Description |
|---|---|---|
get() |
object |
The connection. Opens it on first call; probes it if it sat idle longer than aliveBypassWindow; reopens it once maxLifetime has passed |
peek() |
?object |
The current connection without creating or probing — for diagnostics with no side effects |
evict() |
void |
Drop it; the next get() opens a new one |
close() |
void |
Close it |
For runtimes where the process serves one unit of work at a time. It honours the same lifetimes and probes, so a long-lived CLI worker does not wake up holding a socket the server closed hours ago.
PoolEntry (final class)
new PoolEntry(
object $resource,
float $createdAt,
float $lastUsedAt,
?float $expiresAt,
)What borrow() returns. The connection itself is in $entry->resource; the rest is what
the pool uses to decide about probing and eviction. You never construct one by hand.
PoolPolicy (final readonly class)
new PoolPolicy(
int $maximumPoolSize = 10,
float $connectionTimeout = 15.0,
float $maxLifetime = 1800.0,
float $aliveBypassWindow = 0.5,
float $maxLifetimeJitter = 0.1,
float $housekeepingInterval = 30.0,
float $keepaliveTime = 120.0,
float $idleTimeout = 600.0,
int $minimumIdle = 0,
)
PoolPolicy::default(): PoolPolicy
$policy->housekeepingEnabled(): bool$keepaliveTime is the one parameter that does not read back as given: an unreachable
value — one that reaches maxLifetime, or reaches idleTimeout with no warm floor — is
dropped to 0.0 when the policy is constructed, so the property always shows what the
housekeeper will actually do.
Each parameter is discussed on the Policy page.
PoolException (final class)
The package’s only exception, with three named constructors:
| Constructor | When |
|---|---|
exhausted(float $timeout) |
No connection became free within the timeout — everything is busy |
connectFailed(Throwable $previous) |
The adapter’s create() threw; the original is in getPrevious() |
unusable(int $retired, float $timeout) |
The borrow’s window went on dead connections — the server is reachable but not serving |
The three are deliberately distinct: “all busy” and “all broken” call for opposite
reactions, and an operator told to raise maximumPoolSize while the database refuses to
serve is being sent the wrong way. The number in unusable counts connections thrown
away, not tries: a borrow keeps discarding what it finds until it reaches a live
connection or runs out of time, and how many corpses it buried is the useful signal.
Next
- Quick start — a working example
- Writing an adapter — how to plug in a driver