Symfony Scheduler
Cron-style and periodic task scheduling built on Symfony Messenger
Repository Health
Technical Analysis
Symfony Scheduler lets applications define recurring tasks — cron expressions, fixed intervals, or custom triggers — as regular Symfony Messenger messages, so scheduled work reuses the same dispatch, retry, and worker infrastructure as any other message. Tasks are declared via #[AsCronTask]/#[AsPeriodicTask] attributes or programmatically through RecurringMessage and a Schedule object, and the component ships a SchedulerTransport that generates due messages on demand rather than relying on an external cron daemon polling a table.
Because it’s a Messenger transport, scheduled messages get the same middleware, retry strategies, and multi-worker consumption model as the rest of a Symfony application’s async messaging, avoiding a separate scheduling subsystem.
What You Get
#[AsCronTask],#[AsPeriodicTask], and#[AsSchedule]attributes for declaring scheduled tasks directly on classes/methods- Programmatic
Schedule/RecurringMessageAPI for building schedules without attributes - A
SchedulerTransportMessenger transport that generates due messages instead of requiring a polling worker against a DB table - Trigger primitives (
CronExpressionTrigger,PeriodicalTrigger,JitterTrigger,ExcludeTimeTrigger) for composing scheduling rules - A
debug:schedulerconsole command for inspecting configured schedules and next run times
Common Use Cases
- Running nightly report generation or data cleanup jobs without configuring system cron
- Scheduling periodic API polling or cache-warming tasks alongside existing Messenger consumers
- Adding jitter or excluded time windows to avoid thundering-herd scheduling collisions
- Declaring recurring tasks as attributes directly on the service classes that implement them
- Debugging what’s scheduled and when it will next run via the
debug:schedulercommand
Under The Hood
Architecture - The component models schedules as a Schedule containing one or more RecurringMessages, each paired with a TriggerInterface implementation (CronExpressionTrigger, PeriodicalTrigger, etc.); a Generator/MessageGenerator uses a TriggerHeap to compute the next due message across all recurring tasks, and Messenger/SchedulerTransport implements Symfony Messenger’s transport interface so messenger:consume can pull generated messages like any other queue. Tech Stack - Pure PHP 8.4+ with a hard dependency only on symfony/clock; symfony/messenger, symfony/cache, symfony/lock, and dragonmantank/cron-expression are dev/optional dependencies pulled in by the DI extension when the app registers a scheduler. Code Quality - 20 test files cover the trigger and generator logic; as a subtree split of the monorepo symfony/symfony, it inherits that project’s CI, static analysis, and BC-promise discipline rather than running independent tooling in this read-only mirror. API Design - The attribute-based API (#[AsCronTask('*/5 * * * *')] on a method) lets scheduling live next to the code it triggers with minimal boilerplate, while the lower-level Schedule/RecurringMessage API is available when tasks need to be assembled dynamically; running scheduled tasks still requires a messenger:consume worker process, which is a small conceptual jump for teams used to plain system cron.
Used by 2 apps in this directory
BillaBear
Ecommerce · Invoicing Finance
Self-hostable subscription management and billing platform with Stripe integration, tax automation, configurable workflows, and Twig-based document generation.
Hyvor Relay
Devops · AI Development · Monitoring
Self-hosted, open-source email API that automates DNS, manages SMTP delivery, and provides deep observability — replacing SES, Mailgun, and SendGrid with infrastructure you fully own.