small / swoole-events
Native Swoole event bus with fluent pipelines, coroutine synchronization and Small Collection-backed queues.
Requires
- php: >=8.3
- ext-swoole: *
- small/collection: ^4.0.2
Requires (Dev)
- pestphp/pest: ^4.0
- phpstan/phpstan: ^2.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README

Native Swoole/OpenSwoole event bus without RxPHP. This project succeeds small/swoole-rx-events.
Architecture
EventBus: event routing and RID correlation.EventStream: fluentfilter(),map(),buffer()andsubscribe()pipeline.BackpressureQueue: per-subscription queue backed bysmall/collectionand awakened through coroutine channels.Swoole\Coroutine\Channel: synchronization, blocking and request/response waits.Swoole\Timer: time-based batch flushing.- Immutable
BasicEventvalues.
Example
$subscription = $bus->on('order.created')
->filter(fn ($event) => $event->getPayload()['active'] ?? false)
->map(fn ($event) => $event->getPayload())
->buffer(maxItems: 100, maxWaitMs: 500)
->subscribe(fn ($batch) => persistBatch($batch));
Backpressure is configured per subscriber:
use Small\SwooleEvents\Enum\BackpressureStrategy;
$bus->on('telemetry')->subscribe(
handle(...),
capacity: 1000,
strategy: BackpressureStrategy::DROP_OLDEST,
);
Supported strategies are BLOCK, DROP_OLDEST, DROP_NEWEST and ERROR.
Coroutine request/response
$response = $bus->request(
requestName: 'user.load',
responseName: 'user.loaded',
payload: ['id' => 42],
timeout: 1.0,
);
The response waiter is registered before the request is emitted, eliminating response races.
Development and testing
Like small/swoole-patterns, tests run against Swoole and OpenSwoole inside
reproducible Docker Compose environments (PHP 8.4, Pest, PCOV, GD).
`^bash
Build images and run quality checks + Pest on both runtimes
bash bin/tests
Direct Docker Compose usage
docker compose build unit-test-swoole unit-test-openswoole docker compose run --rm unit-test-swoole sh -lc 'composer install && composer quality && composer unit-tests' docker compose run --rm unit-test-openswoole sh -lc 'composer install --ignore-platform-req=ext-swoole && composer unit-tests' `^
The badges above use the same local PNG generation process as small-swoole-patterns:
composer-scripts/unit-tests starts with a failing test badge, changes it to green
only when Pest succeeds, and composer-scripts/check-coverage regenerates the
coverage percentage image from the XML coverage report. Their committed images
represent the last reported run. Detailed reports are in coverage/ (ignored by Git).
PHPStan is run at level max in the Swoole container. OpenSwoole has incompatible reflection signatures for timer helpers, so that runtime runs the full Pest suite and coverage gate without rerunning static analysis.
The test suites cover event immutability and IDs, subscription lifecycle, backpressure strategies, filtering/mapping, batching, timed flushes, request/reply, RID matching, timeouts, and coroutine synchronization. Run:
^bash
docker compose run --rm unit-test-swoole vendor/bin/pest --testsuite=Unit
docker compose run --rm unit-test-swoole vendor/bin/pest --testsuite=Functional
^
Releases
From a clean main branch, bash bin/release runs both runtime test suites,
creates an annotated SemVer tag, and pushes the tag to origin:
^bash
bash bin/release --patch
bash bin/release --minor
bash bin/release --major
^
The version is derived from the latest existing SemVer tag; no release is performed if the working tree is dirty or if the test command fails. Release tag creation/pushing is intentional and is not part of the test command.
License
Copyright 2026 - Sébastien Kus. The original code in this repository is licensed under MIT.
Third-party licensing: The required small/collection dependency is now licensed under MIT as well. Its copyright and license notices remain applicable; see the small/collection repository.