Download the PHP package phpdot/pool without Composer
On this page you can find all versions of the php package phpdot/pool. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Informations about the package pool
phpdot/pool
Generic coroutine-safe connection pool for Swoole. Holds any object. Channel-based with idle cleanup, optional heartbeat, and leak prevention.
Table of Contents
- Install
- Architecture
- How It Works
- Package Structure
- ConnectorInterface
- Pool
- Lifecycle
- Borrow
- Release
- Discard
- Stats
- Close
- PoolConfig
- Idle Cleanup
- Heartbeat
- Edge Cases
- Double Release
- Pool Exhaustion
- Connect Failure During Init
- Borrow After Close
- Race Condition Prevention
- Framework Wiring
- API Reference
- ConnectorInterface API
- Pool API
- PoolConfig API
- PoolStats API
- Exceptions API
- License
Install
| Requirement | Version |
|---|---|
| PHP | >= 8.3 |
| ext-swoole | >= 6.0 |
Architecture
How It Works
The pool is built on Swoole\Coroutine\Channel — a coroutine-safe bounded FIFO queue. pop() suspends only the calling coroutine (not the worker process). push() wakes the next waiting coroutine. Lock-free at the C level.
Package Structure
8 files. One dependency (ext-swoole).
ConnectorInterface
The pool doesn't know what it's pooling. The connector tells it how to create, check, and close objects:
Implementations live in the framework kernel, not in this package:
Pool
Lifecycle
Borrow
- If the Channel has idle connections → returns one immediately
- If empty but below
maxConnections→ creates a new one (slot reserved before I/O to prevent race) - If at capacity → suspends the coroutine until a connection is released
- If timeout → throws
BorrowTimeoutException - If pool closed → throws
PoolClosedException
Release
Returns the connection to the Channel. Double release is silently ignored (tracked via spl_object_id). If the pool was closed while the connection was borrowed, the connection is closed instead.
Discard
Permanently closes the connection. Not returned to the Channel. Decrements the pool count, allowing a new connection to be created on the next borrow.
Stats
Close
Stops timers, closes all idle connections. Borrowed connections are closed when released/discarded. Idempotent.
PoolConfig
Total database connections = workers x maxConnections. 4 workers x 10 max = 40 max connections.
Idle Cleanup
Purpose: shrink the pool after traffic spikes. Not for connection health.
When maxIdleTime > 0.0, a timer runs every idleCheckInterval seconds:
- Skip if coroutines are waiting for connections
- Pop idle items from Channel
- Close items idle longer than
maxIdleTime(only if aboveminConnections) - Push back the rest
- Refill to
minConnectionsif needed
Set maxIdleTime: 0.0 to disable.
Heartbeat
Purpose: safety net for dead connections. Disabled by default.
When heartbeatInterval > 0.0, a timer checks idle connections via ConnectorInterface::isAlive():
- Skip if coroutines are waiting
- Pop all idle items
- Close dead ones (
isAlive() === false) - Push back alive ones
- Refill to
minConnections
isAlive() should be lightweight. A single round-trip ping (e.g. SELECT 1) is acceptable and is the recommended implementation — for typical drivers, only a server-side check detects connections killed by wait_timeout, firewall idle drops, or server restarts.
Validate-on-Borrow
Purpose: catch dead connections at the moment they're handed to a caller, before the caller spends a query learning the connection is broken. TTL-gated to avoid pinging on every hot-path borrow.
When validateOnBorrowAfterIdle ≥ 0.0 and a popped connection has been idle ≥ that many seconds, the pool calls isAlive() before returning it. If dead, the connection is closed and the borrow loop continues — either popping another or creating a fresh one.
Hot borrow/release cycles skip the check; only "stale" connections get pinged.
Validate-on-Return
Purpose: belt-and-suspenders — catch connections that have died mid-use before they're put back in the pool.
When validateOnReturn = true, release() calls isAlive() on the returned connection. Dead connections are closed (not re-pooled), and the pool refills toward minConnections.
Off by default — the connection just succeeded a query, so the check is usually redundant. Enable for "no tolerance" production stances.
Edge Cases
Double Release
Tracked via spl_object_id. Second release() on the same connection is silently ignored. Prevents Channel corruption.
Pool Exhaustion
All connections borrowed, new coroutine calls borrow():
- Coroutine is suspended (not the worker process)
- Other coroutines continue running
- When any coroutine releases → waiting coroutine resumes
- If
borrowTimeoutexpires →BorrowTimeoutException
Connect Failure During Init
If connector->connect() throws during init(), the error is skipped. The pool starts with fewer connections. On-demand creation in borrow() fills the gap.
Borrow After Close
Throws PoolClosedException immediately.
Race Condition Prevention
On-demand creation in borrow() increments currentCount before calling connect() (which yields on I/O). This prevents multiple coroutines from passing the < maxConnections check simultaneously — the slot is reserved before any yield point.
Framework Wiring
The developer never touches the pool. The framework kernel wires it:
Developer code is identical in both modes:
API Reference
ConnectorInterface API
Pool API
PoolConfig API
PoolStats API
Exceptions API
License
MIT