mleczakm / swoole-bundle-scheduler
Run Symfony Scheduler inside the Swoole HTTP server on a Swoole\Timer::tick() loop instead of a blocking messenger:consume worker.
Package info
github.com/mleczakm/swoole-bundle-scheduler
Type:symfony-bundle
pkg:composer/mleczakm/swoole-bundle-scheduler
Requires
- php: ^8.3
- ext-swoole: *
- psr/cache: ^2.0 || ^3.0
- psr/clock: ^1.0
- psr/event-dispatcher: ^1.0
- psr/log: ^3.0
- swoole-bundle/swoole-bundle: ^0.32
- symfony/cache: ^7.4 || ^8.0
- symfony/clock: ^7.4 || ^8.0
- symfony/config: ^7.4 || ^8.0
- symfony/dependency-injection: ^7.4 || ^8.0
- symfony/http-kernel: ^7.4 || ^8.0
- symfony/messenger: ^7.4 || ^8.0
- symfony/scheduler: ^7.4 || ^8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.94
- macpaw/symfony-health-check-bundle: ^2.1
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.1
- phpstan/phpstan-phpunit: ^2.0
- phpunit/phpunit: ^11.5 || ^12.5
- symfony/framework-bundle: ^7.4 || ^8.0
- symfony/lock: ^7.4 || ^8.0
Suggests
- macpaw/symfony-health-check-bundle: Enables the /health scheduler heartbeat check (swoole_bundle_scheduler.health_check)
- symfony/lock: Enables the opt-in cross-process tick lock (swoole_bundle_scheduler.lock)
Provides
None
Conflicts
None
Replaces
None
README
Run Symfony Scheduler inside the Swoole
HTTP server, on a Swoole\Timer::tick() loop - no separate messenger:consume scheduler_*
worker process to run, supervise, restart, or pay memory for.
A companion package to swoole-bundle/swoole-bundle.
Install
composer require mleczakm/swoole-bundle-scheduler
// config/bundles.php SwooleBundle\Scheduler\SwooleBundleSchedulerBundle::class => ['all' => true],
# config/packages/swoole_bundle_scheduler.yaml swoole_bundle_scheduler: enabled: true interval: 60
Define a schedule the normal Symfony way (#[AsSchedule] + ScheduleProviderInterface) and
it is polled automatically. Restart the Swoole server to pick it up.
What you get
- Polls every
#[AsSchedule]provider off the Swoole event loop, dispatching due messages through the message bus with the samePreRunEvent/PostRunEvent/FailureEventas Symfony's own worker. - A failed tick is logged and retried next interval - it never crashes the server.
- Overlapping ticks are skipped, not queued.
- Each tick resets the pooled stateful services it touches, via the swoole-bundle's own coroutine boundary machinery.
Opt-in production hardening
All disabled by default; enable per app when you hit the failure mode:
| Option | Defends against |
|---|---|
lock |
The tick firing in a second OS process (Swoole manager during reload) and double-dispatching |
watchdog |
A hung Scheduler::run() wedging the scheduler forever behind a never-freed semaphore |
heartbeat + health_check |
A wedged scheduler staying invisible while /health keeps passing |
pre_run / after_tick |
App-specific readiness checks / state resets around each tick |
Docs
- docs/usage.md - walkthrough, full config reference, caveats
- docs/production-hardening.md - when and how to enable each hardening option
- examples/ - copy-paste schedule, message, handler, config, custom scheduler
Requirements
- PHP >= 8.3,
ext-swoole swoole-bundle/swoole-bundle^0.32with coroutines enabledsymfony/scheduler+symfony/messengersymfony/lock(only for thelockoption)macpaw/symfony-health-check-bundle(only for thehealth_checkoption)
License
MIT