PHPackages                             phpdot/pool - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. phpdot/pool

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

phpdot/pool
===========

Generic coroutine-safe connection pool for Swoole. Holds any object. Channel-based with idle cleanup, optional heartbeat, and leak prevention.

v0.1.0(1mo ago)00MITPHPPHP &gt;=8.5

Since Jul 18Pushed 1mo agoCompare

[ Source](https://github.com/phpdot/pool)[ Packagist](https://packagist.org/packages/phpdot/pool)[ RSS](/packages/phpdot-pool/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (33)Versions (8)Used By (0)

phpdot/pool
===========

[](#phpdotpool)

Generic, coroutine-safe connection pool for Swoole. Holds objects of any type behind a `Swoole\Coroutine\Channel`, so borrowing and releasing are lock-free at the C level. Creates connections up to a cap, reaps idle ones, optionally heartbeats them, validates on borrow and return, and prevents leaks and cross-coroutine sharing — created in `onWorkerStart`, closed in `onWorkerStop`.

Table of Contents
-----------------

[](#table-of-contents)

- [Requirements](#requirements)
- [Installation](#installation)
- [Usage](#usage)
    - [Define a Connector](#define-a-connector)
    - [Create and Initialize](#create-and-initialize)
    - [Borrow and Release](#borrow-and-release)
    - [Discard](#discard)
    - [Configuration](#configuration)
    - [Idle Cleanup](#idle-cleanup)
    - [Heartbeat](#heartbeat)
    - [Validate on Borrow and Return](#validate-on-borrow-and-return)
    - [Stats](#stats)
    - [Shutdown and Draining](#shutdown-and-draining)
    - [Framework Wiring](#framework-wiring)
- [Architecture](#architecture)
- [Testing](#testing)
- [License](#license)

Requirements
------------

[](#requirements)

RequirementConstraintPHP`>= 8.5``ext-swoole``>= 6.2``phpdot/contracts``^0.1`Installation
------------

[](#installation)

```
composer require phpdot/pool
```

Usage
-----

[](#usage)

### Define a Connector

[](#define-a-connector)

The pool does not know what it pools. A connector — implementing `PHPdot\Contracts\Pool\ConnectorInterface` (shipped by `phpdot/contracts`) — tells it how to create, health-check, and close the underlying object.

```
use PHPdot\Contracts\Pool\ConnectorInterface;

final class RedisConnector implements ConnectorInterface
{
    public function connect(): object
    {
        $redis = new \Redis();
        $redis->connect('127.0.0.1', 6379);

        return $redis;
    }

    public function isAlive(object $connection): bool
    {
        return $connection->ping() === true; // lightweight server round-trip
    }

    public function close(object $connection): void
    {
        $connection->close();
    }
}
```

`isAlive()` should be a single cheap round-trip (e.g. `PING`, `SELECT 1`); only a server-side check catches connections killed by idle timeouts, firewall drops, or restarts.

### Create and Initialize

[](#create-and-initialize)

`init()` pre-creates `minConnections` and starts the timers. It **must** run inside a Swoole coroutine (typically `onWorkerStart`).

```
use PHPdot\Pool\Pool;
use PHPdot\Pool\PoolConfig;

$pool = new Pool(new RedisConnector(), new PoolConfig(minConnections: 4, maxConnections: 20));
$pool->init();
```

### Borrow and Release

[](#borrow-and-release)

Borrow a connection, use it, then return it. On exhaustion `borrow()` waits up to `borrowTimeout`, growing the pool on demand up to `maxConnections`.

```
$redis = $pool->borrow();       // object, or throws BorrowTimeoutException / PoolClosedException

try {
    $redis->set('key', 'value');
} finally {
    $pool->release($redis);     // return for reuse; double release is ignored
}
```

- `borrow(): object` — throws `PHPdot\Pool\Exception\BorrowTimeoutException` when none becomes available within `borrowTimeout`, or `PHPdot\Pool\Exception\PoolClosedException` after `close()`.
- `release(object $connection): void` — returns the connection to the pool; releasing an unknown or already-released connection is silently ignored.

### Discard

[](#discard)

Permanently close a connection that must not be reused (a broken one), freeing its slot.

```
$pool->discard($redis);         // close + free the slot, never re-pool
```

### Configuration

[](#configuration)

`PoolConfig` is an immutable value object (also discoverable as `#[Config('pool')]`).

```
use PHPdot\Pool\PoolConfig;

new PoolConfig(
    minConnections: 2,                  // pre-created on init; pool never shrinks below this
    maxConnections: 10,                 // hard cap per worker
    borrowTimeout: 3.0,                 // seconds to wait when exhausted
    maxIdleTime: 300.0,                 // seconds before an idle connection is reaped (0.0 = off)
    idleCheckInterval: 30.0,            // seconds between idle-cleanup runs
    heartbeatInterval: 0.0,             // seconds between heartbeats (0.0 = off)
    validateOnBorrowAfterIdle: 5.0,     // isAlive() on borrow after N idle secs; 0.0 = always;  0.0`, a timer every `idleCheckInterval` seconds closes connections idle longer than `maxIdleTime`, never dropping below `minConnections`. Connections in use are untouched.

### Heartbeat

[](#heartbeat)

When `heartbeatInterval > 0.0`, a separate timer calls `isAlive()` on idle connections and closes dead ones, refilling toward `minConnections`. Off by default — enable it for backends that drop idle connections aggressively.

### Validate on Borrow and Return

[](#validate-on-borrow-and-return)

- **On borrow** — when `validateOnBorrowAfterIdle >= 0.0` and a popped connection has been idle at least that many seconds, `isAlive()` is called before hand-off; a dead one is closed and the borrow loop tries again. `0.0` validates every borrow; a negative value disables it.
- **On return** — when `validateOnReturn` is `true` (default), `release()` calls `isAlive()` and discards (rather than re-pools) dead connections, so a connection poisoned mid-use cannot be handed straight back out.

### Stats

[](#stats)

`stats()` returns an immutable `PoolStats` snapshot for monitoring and health checks.

```
$s = $pool->stats();
$s->active; $s->idle; $s->total;                     // live counts
$s->borrowCount; $s->releaseCount; $s->discardCount; // lifetime counters
$s->createCount; $s->closeCount; $s->timeoutCount; $s->waitingCount;
```

### Shutdown and Draining

[](#shutdown-and-draining)

- `close(): void` — full synchronous shutdown: stop timers, drain and close idle connections; borrowed connections close on their later release. `isClosed(): bool` reports the state.
- `suspendTimers(): void` — stop the idle/heartbeat timers **without** closing the pool, so in-flight `borrow()` calls still complete against live connections. Use it on `onWorkerExit`during a graceful drain; the OS closes pooled connections when the worker exits.

### Framework Wiring

[](#framework-wiring)

```
$server->on('workerStart', fn () => $pool->init());
$server->on('workerExit',  fn () => $pool->suspendTimers()); // keep serving through the drain
$server->on('workerStop',  fn () => $pool->close());         // full teardown
```

Architecture
------------

[](#architecture)

 ```
graph TD
    CALLER["Caller coroutineborrow() → use → release()"]

    subgraph Pool
        direction TB
        CHAN["Coroutine Channel of PooledItemCoroutine-safe bounded FIFO.pop() suspends only the caller,push() wakes the next waiter"]
        GROW["On-demand growthreserve the slot before connect(),capped at maxConnections"]
        VALID["ValidationisAlive() on borrow-after-idleand on return"]
        TIMERS["Timersidle cleanup + optional heartbeat"]
    end

    CONN["ConnectorInterfacefrom phpdot/contracts:connect / isAlive / close"]
    CFG["PoolConfigConfig('pool') — sizing, timeouts,idle cleanup, heartbeat, validation"]
    STATS["PoolStatsImmutable monitoring snapshot"]

    CALLER --> Pool
    CFG --> Pool
    Pool --> CONN
    Pool --> STATS
```

      Loading `Pool` is built on `Swoole\Coroutine\Channel`, a coroutine-safe bounded FIFO: `pop()` suspends only the calling coroutine (never the worker process), `push()` wakes the next waiter, and the lock is at the C level. Growth reserves the slot (`currentCount++`) before the yielding `connect()`, so concurrent coroutines cannot overshoot `maxConnections`. The connection type is supplied entirely through `ConnectorInterface`, which lives in `phpdot/contracts` — this package depends on the contract, never on a concrete driver.

Testing
-------

[](#testing)

The package is standalone-testable:

```
composer install
composer test        # PHPUnit
composer analyse     # PHPStan, level max + strict rules
composer cs-check    # PHP-CS-Fixer
composer check       # all three
```

License
-------

[](#license)

MIT.

**This repository is a read-only mirror**, generated by CI from [phpdot/monorepo](https://github.com/phpdot/monorepo). [Pull requests](https://github.com/phpdot/monorepo/pulls)and [issues](https://github.com/phpdot/monorepo/issues) belong in the monorepo.

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance94

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 85.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~17 days

Recently: every ~5 days

Total

7

Last Release

32d ago

Major Versions

v0.0.1 → v1.0.02026-05-02

PHP version history (3 changes)v0.0.1PHP &gt;=8.3

v1.0.3PHP &gt;=8.4

v0.1.0PHP &gt;=8.5

### Community

Maintainers

![](https://www.gravatar.com/avatar/62e82421bda4b5d6ba9a47ba6d88caca060dcd0d1a2862f351f3a97657385db0?d=identicon)[phpdot](/maintainers/phpdot)

---

Top Contributors

[![phpdot](https://avatars.githubusercontent.com/u/252500?v=4)](https://github.com/phpdot "phpdot (6 commits)")[![o3AM](https://avatars.githubusercontent.com/u/252500?v=4)](https://github.com/o3AM "o3AM (1 commits)")

---

Tags

swoolecoroutinepoolchannelconnection-pool

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/phpdot-pool/health.svg)

```
[![Health](https://phpackages.com/badges/phpdot-pool/health.svg)](https://phpackages.com/packages/phpdot-pool)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
