padam87/cron-bundle
Symfony bundle for defining and running cron jobs as annotated services. Schedule tasks with a simple @Cron annotation, prevent overlapping runs with locks, and execute jobs via a console command, keeping scheduled work organized, logged, and easy to test inside your Symfony app.
First, set expectations: padam87/cron-bundle is a Symfony bundle, not a Laravel package. If you're a Laravel developer, you already have an equivalent in Illuminate\Console\Scheduling\Schedule—and both ultimately lean on the same dragonmantank/cron-expression parser, so every expression you write here is portable to $schedule->command(...)->cron('...'). Think of this package as "the Symfony scheduler," and evaluate it where you actually have a Symfony kernel or a bare Symfony Console app.
Minimal steps:
composer require padam87/cron-bundle
Register the bundle (Symfony): add Padam87\CronBundle\Padam87CronBundle to config/bundles.php.
Read these first, in this order:
Cron/ — Job, Schedule, and the manager that collects and fires due jobs.Command/ — the padam87:cron:run entrypoint and any "list / run one job" commands.Annotation/Cron.php — how a console command is tagged with a schedule.DependencyInjection/Configuration.php — the actual config tree (locking, logging, mailer).First use case: annotate a console command with a cron expression, then register one system crontab line:
* * * * * php /path/to/bin/console padam87:cron:run
Verify with the bundle's list command (padam87:cron:list) that your job is registered and shows the intended next-run time.
Single runner, many jobs. This is the same model as Laravel's schedule:run: your OS crontab knows nothing about individual jobs; it invokes the runner every minute and the bundle decides what is due. Keep exactly one crontab entry and let the schedule live in code/config, version-controlled and reviewable in PRs.
Annotation-per-command (primary pattern). Tag the console command you already own with a schedule annotation on execute() and let the bundle discover it. This is the closest analog to writing jobs inside app/Console/Commands and scheduling them in Kernel::schedule()—the difference is co-location: schedule and implementation sit in the same file, which reduces drift.
Config-declared jobs. Use configuration entries for commands you don't own (vendor commands, framework internals). This is the equivalent of scheduling someone else's Artisan command from Kernel.php.
Overlap protection via locks. Long-running jobs should opt into per-job locking so a second invocation doesn't fire while the first is still running. Configure the lock backend once and enable it per job; this is the direct counterpart of Laravel's ->withoutOverlapping().
Manual replay. Use the runner's single-job invocation (padam87:cron:run <job-name>) to backfill, reproduce a failure, or smoke-test in staging without waiting for the minute boundary.
If you're bridging into Laravel (rarely worth it). Don't run both this bundle and Laravel's scheduler against the same host—you'll get duplicate execution. If you must adopt it, wrap it as a thin Artisan command that shells out to bin/console padam87:cron:run, but the pragmatic move is to port expressions into Kernel::schedule() and drop the bundle.
Workflow suggestion: assert job registration in CI with the list command before deploy, so a renamed command class or dropped annotation fails the build rather than silently disappearing from the schedule.
config/padam87.php publish step. composer require alone does nothing in a Laravel app—another reason to port patterns rather than install.#[Cron(...)] is supported or whether you still need doctrine/annotations. Pin and test; this package has a small maintainer surface (11 stars, 0 dependents) and won't track framework deprecations for you.*/5 * * * *, not the crontab.date.timezone for the CLI SAPI, don't assume app.timezone applies—same class of bug Laravel devs hit with ->timezone().-vvv, use the list command to inspect next-run times, then read the Command/ class to see exactly how "due" jobs are filtered—there's no Laravel Telescope equivalent here, so source reading is your debugger.Event/ directory and a configurable lock manager. Job lifecycle events (if dispatched) are the clean hook for metrics and alerting; a custom lock backend is the hook for distributed environments.Bottom line for a Laravel developer: this is a competent reimplementation of the scheduler idea for Symfony console, and the concepts transfer one-to-one. Adopt it when you're in Symfony; in Laravel, translate the cron expressions and use Schedule.
How can I help you explore Laravel packages today?