Package · cpool

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)

php
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)

php
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 connection. Below the cap it creates one; at the cap it waits up to connectionTimeout. Throws exhausted() on timeout, unusable() if connections keep failing the probe
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)

php
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)

php
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)

php
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 = 0.0,
  float $idleTimeout = 0.0,
  int   $minimumIdle = 0,
)

PoolPolicy::default(): PoolPolicy
$policy->housekeepingEnabled(): bool

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 $attempts) Connections keep failing the probe — the database is not answering

exhausted and unusable are different diagnoses: the first says “your code is holding everything”, the second says “the connections themselves are bad”.

Next