Policy
PoolPolicy is an immutable value object. Every setting has a default; pass named
arguments only for what you are changing.
use Flytachi\Winter\CPool\PoolPolicy;
new PoolPolicy(maximumPoolSize: 20, maxLifetime: 600.0);
PoolPolicy::default(); // all defaultsCapacity
| Parameter | Default | What it does |
|---|---|---|
maximumPoolSize |
10 |
Hard cap on the number of open connections |
connectionTimeout |
15.0 |
How long a borrower waits before getting exhausted() |
That is one decision, not two. The cap turns “too many connections” from a refusal on the database side into a queue on the application side; the timeout decides how long that queue is allowed to grow before a request gives up.
How to size it: the cap is a property of the database, divided by the number of
workers talking to it. Four Swoole workers against PostgreSQL with
max_connections = 100, leaving room for migrations and psql, is closer to
maximumPoolSize: 15 than to 100.
A pool at its cap is not always too small
Before raising the limit, look for a borrow() without a matching release(): every
such leak permanently shrinks the working size of the pool by one, and the symptom looks
identical.
Lifetime
| Parameter | Default | What it does |
|---|---|---|
maxLifetime |
1800.0 |
A connection older than this is evicted on borrow |
maxLifetimeJitter |
0.1 |
The fraction of maxLifetime the deadline is spread over |
Why evict a healthy connection at all: proxies, load balancers and failover addresses move underneath long-lived sockets. A connection opened an hour ago may answer perfectly while pointing at a server being rotated out. Reopening is how you follow infrastructure the pool cannot see.
The jitter is not decoration. Ten connections created at startup with the same deadline expire within the same second — and the application stalls while all ten reconnect. Ten percent of half an hour stretches that over three minutes.
Liveness probing
| Parameter | Default | What it does |
|---|---|---|
aliveBypassWindow |
0.5 |
Skip the probe for a connection used recently |
Set 0.0 and the probe runs on every borrow: correct, and it doubles the round trips of
a busy service. Raise it and a broken socket survives a little longer before it is
noticed. The default assumes that a connection which answered half a second ago is
alive; if the database died inside that window the request fails, and the caller evicts
the connection itself.
Background housekeeping
| Parameter | Default | What it does |
|---|---|---|
housekeepingInterval |
30.0 |
How often the sweep runs |
keepaliveTime |
0.0 |
Ping connections idle for longer than this (0 — off) |
idleTimeout |
0.0 |
Close connections idle for longer than this (0 — off) |
minimumIdle |
0 |
Never drop below this many |
housekeepingEnabled() is false until keepaliveTime or idleTimeout is set, and the
timer is only armed under Swoole. With the defaults there is no timer at all — an
idle pool costs nothing.
You turn keepaliveTime on when a firewall or the database kills idle connections: a
periodic ping stops them from dying quietly between requests. idleTimeout is for bursty
traffic, where holding the peak-sized pool all night is wasteful; that is also when you
set minimumIdle, so the next burst does not start from zero.
The two settings pull in opposite directions: one keeps connections alive, the other lets
them go. Enabling both makes sense — keep a warm minimum, release the rest — when
minimumIdle is set.
Next
- API reference — where each setting is applied
- Writing an adapter —
validate()under the bypass window