Package · cpool

Policy

PoolPolicy is an immutable value object. Every setting has a default; pass named arguments only for what you are changing.

php
use Flytachi\Winter\CPool\PoolPolicy;

new PoolPolicy(maximumPoolSize: 20, maxLifetime: 600.0);

PoolPolicy::default();     // all defaults

Capacity

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