Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Cron Bundle Laravel Package

whatwedo/cron-bundle

A Symfony bundle for managing scheduled cron jobs in code. Define recurring tasks and run console commands on configurable schedules, keeping cron configuration versioned and integrated with your Symfony application.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and register

composer require whatwedo/cron-bundle

On Symfony Flex the bundle is auto-registered; otherwise add it to config/bundles.php. Then look at bin/console list whatwedo (or debug:container --tag=…) to confirm the bundle's runner and list commands are available — that tells you the exact command names for the version you pinned.

Where to look first

  1. The README's minimal example (attribute + system cron entry).
  2. The attribute/annotation class used to declare a schedule (e.g. #[CronJob('*/5 * * * *')]).
  3. The CronManager-style service and the console command that fans jobs out — this is the actual dispatcher.
  4. Any config tree under config/packages/whatwedo_cron.yaml.

The core mental model (vs. Laravel)

Laravel's Kernel::schedule() is pull: one system cron hits schedule:run every minute and the framework decides what's due. This bundle is the same idea for Symfony: you keep one system crontab entry pointing at the bundle's run command, and schedule individual Symfony console commands declaratively by decorating them with a cron expression. If you're coming from Laravel, think "schedule:run + ->everyFiveMinutes()", except the schedule lives on the command class rather than in a central file.

First use case

Pick a harmless existing command — cache warmup, a report generator, a cleanup task — annotate it with a cron expression, run the bundle's "list" command to confirm it's discovered, then invoke the runner manually with -vvv before wiring it into crontab:

* * * * * cd /path/to/app && php bin/console <bundle>:cron:run >> /var/log/cron.log 2>&1

Implementation Patterns

Attribute-per-command scheduling. The idiomatic use is to keep scheduling metadata next to the command it schedules. This scales well for domain commands (app:sync-orders, app:purge-sessions) because the cron expression is versioned with the code and reviewed in the same PR as the logic.

Single dispatcher, many jobs. Never create one crontab line per command. One minute-level system cron invoking the bundle's runner means jobs are centrally observable, testable via the CLI, and portable across hosts. This is the pattern that makes the bundle worth using over hand-written crontab entries.

Autoconfiguration / tags. Discovery depends on commands being registered in the container (usually via console.command tagging and autoconfigure). If a command is defined lazily or in a compiler pass, verify it appears in the bundle's list output — otherwise the attribute is silently ignored.

Overlap protection. Any job that can run longer than its interval needs a lock. Check whether the runner ships locking; if not, wrap the command with symfony/lock (LockableTrait or a LockFactory guard) so a slow run doesn't stack. In multi-container deployments this must be a shared lock store (Redis/DB), not filesystem.

Environment gating. Register the runner only in environments where a scheduler should exist, and consider disabling scheduling in test/dev via config so fixture-heavy test suites don't fire real jobs.

Output and observability. Cron jobs that swallow output are undebuggable. Pattern: have each command log a start/finish line with duration through Monolog, and let the run command stream to stdout so the system cron redirect captures failures. Pair with a heartbeat (healthchecks.io, Sentry cron monitor) on the dispatcher itself — if the dispatcher dies, nothing alerts you otherwise.

Coexistence with Symfony Scheduler. If you're on Symfony 6.3+, the native Scheduler component covers the same ground with first-class Messenger integration. A common migration pattern is to keep this bundle for legacy attribute-declared commands and move new schedules to the native scheduler incrementally, rather than doing a flag-day rewrite.

Testing. Exercise the CronManager/dispatcher directly in a kernel test: inject a frozen clock, assert which commands are considered due at a given timestamp rather than shelling out to crontab.

Gotchas and Tips

  • Adoption risk is the headline. Zero stars and zero dependents means no community validation. Pin an exact version in composer.json, read the dispatcher source once (it's small), and be prepared to vendor it. For a greenfield project on modern Symfony, prefer the native Scheduler component.
  • Cron expression semantics. Standard 5-field cron has minute granularity and no seconds. If you need sub-minute cadence this bundle will not give it (nor will cron). Double-check timezone assumptions — expressions are typically evaluated in the server/PHP timezone, not per-job.
  • "Due" state has to live somewhere. Determine where the bundle persists last-run timestamps (cache, filesystem, DB). Filesystem state breaks on ephemeral containers and multi-node setups; cache state can be flushed and cause duplicate runs. This is the single most common production surprise.
  • Silent non-discovery. A command missing from the list output usually means it isn't a tagged container service or is excluded by autoconfigure rules. Start debugging there before assuming the cron syntax is wrong.
  • Overlap and drift. Without a lock, a job that occasionally exceeds its interval will run twice concurrently and corrupt state. Add locking defensively even if the bundle claims to handle it.
  • Deploy behaviour. On a rolling deploy, both old and new containers may run the dispatcher. Either restrict the dispatcher to a single node via config/env, or rely on a distributed lock keyed per job.
  • Debugging workflow. Run the list command → run the dispatcher manually with -vvv → run the individual command directly. If the command works standalone but not via the dispatcher, the problem is scheduling/discovery, not your command.
  • Extension points. The dispatcher service and the attribute are the two seams to customize (e.g. subclasses or decorators for custom failure handling/retries). Because the package is small, subclassing/decorating internally is often easier than filing upstream issues.
  • Comparison shopping. Evaluate symfony/scheduler + Messenger, cron/cron, and dragonmantank/cron-expression (which most of these bundles depend on) before committing — the ecosystem around this bundle is thin, and the same cron-parsing capability is one composer line away if you want to build the dispatcher yourself in ~50 lines.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect