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

psf1/cron-bundle

psf1/cron-bundle is a Symfony bundle for defining, scheduling, and running cron jobs from your application. It helps manage recurring tasks in one place, reducing reliance on system crontabs and making scheduled work easier to configure and maintain.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: psf1/cron-bundle is a Symfony bundle, not a Laravel package. It ships no ServiceProvider, no facade, and no Eloquent support — it assumes Symfony's DependencyInjection container, the Console component, and (typically) Doctrine ORM for persistence. It remains effectively unmaintained by community standards (zero stars, no dependents), and 1.0.2 is a patch-level release that adds a feature and a README refresh — not a revival. The realistic question isn't "how do I install this into Laravel" but "do I want to port its model, or just reproduce it with Laravel-native tools?" The 1.0.2 answer is still: reproduce it. Laravel's container already gives you the one thing this release added.

If you still want to use it directly:

  1. composer require psf1/cron-bundle — expect Symfony components (and likely Doctrine) to come along.
  2. In a Symfony app, register the bundle in config/bundles.php and run whatever install/migration command it ships. In Laravel, you'd have to instantiate its core services by hand inside a service provider you write yourself — and since 1.0.2, also hand-register whatever constructor dependencies your job classes declare, because you're the container now.
  3. Provide a cron-job table/entity — fields are typically name, command (or request), schedule (cron expression), enabled, and some notion of lastRun / nextRun.
  4. Register one system crontab entry (* * * * *) that calls the bundle's "tick" command; the bundle then evaluates every persisted job and dispatches the ones that are due.

Where to look first:

  • The Entity/ (or Model/) directory — that's the schema you'll be adapting or porting.
  • The console command that runs the tick loop — that's the execution contract you actually depend on.
  • The manager/repository service used to add, enable, disable, and delete jobs.
  • After 1.0.2, the job-class instantiation path — the place that used to new a job and now asks the container for it. That is the file that tells you how far the DI support actually reaches.

First use case: per-tenant scheduling. A user creates a recurring report or webhook; you persist a row with an expression like */15 * * * * and the command or URL to invoke. The tick command does the rest.

Implementation Patterns

  • Single tick, DB-driven jobs. Don't generate a crontab line per job (the classic crontab -e mutation pattern) unless you truly must. One minute-level tick command that reads due jobs from the database is more portable, testable, and avoids shelling out on every user action.
  • Eloquent wrapper as the "Laravel mode". In practice, wrapping the concept in your own Eloquent model plus dragonmantank/cron-expression (CronExpression::factory($expr)->isDue()) reproduces ~90% of what this bundle does and avoids mixing Doctrine and Eloquent in one app. This is the pattern most Laravel devs will end up with.
  • Store class names, let the container build them. 1.0.2's headline change — dependency injection in cron jobs — is the bundle catching up to something Laravel does by default: app()->make($jobClass) resolves constructor dependencies automatically, including queued jobs. So persist a job class name (or a job payload) rather than a raw shell command, and your runner dispatches it. You get DI, retries, timeouts, and logs for free instead of reimplementing them around exec().
  • Two trigger paths. The bundle explicitly supports adding jobs "with requests, or command" — an HTTP endpoint for user-facing scheduling and a console command for ops/seed. Mirror that split: a controller for create/update/delete, an Artisan command for bulk operations and backfills.
  • Dispatch, don't inline. Even once job classes are container-resolved, keep the tick loop short: resolve/validate the row, dispatch, move on. Don't run a job's work inside the scheduler process, or a single slow job stalls every other due entry in that minute.
  • Lock per job. Use Cache::lock("cron:{$job->id}") (or a DB advisory lock) so a slow run can't double-fire when the next cron minute overlaps.
  • Observability fields. Persist last_started_at, last_finished_at, last_status, and last_output. These are the columns the bundle is most likely not to give you and the ones you'll miss most in production.

Gotchas and Tips

  • Framework mismatch. Symfony's console/DI plus Doctrine inside a Laravel app is a lot of ceremony for a low-value dependency. Unless the host app is already Symfony, implement the pattern natively — don't port the bundle.
  • DI support is Symfony-shaped. "Allow dependency injection in cron jobs" means the bundle now asks the Symfony service container for job instances. In a hand-rolled Laravel service provider shim you must replicate that resolution yourself (app()->make(...)), and the job classes must be resolvable — any new MyJob() in ported code now breaks the moment a job declares a constructor arg. Also verify the autowiring actually applies to your job classes; a README-level claim is not the same as coverage across the tick path.
  • Semver is not a contract here. A new capability shipped as a 1.0.2 patch. Don't infer "safe to upgrade blindly" from the version number, and pin the exact version if you depend on it.
  • Still unmaintained. Zero stars, zero dependents, and a single low-activity maintainer. Expect stale dependency constraints against modern Symfony/Laravel. Vendor or pin it if you must use it; otherwise plan the exit before you start.
  • System crontab permissions. Any design that mutates the real crontab requires the PHP user to have crontab rights and breaks inside containers and most managed hosts. The DB + tick approach sidesteps this entirely — prefer it.
  • Timezone handling. Cron expressions are typically evaluated in the server TZ unless you apply a per-job TZ. For user-facing scheduling that is almost always wrong by default. Store timezone on the row and evaluate with it.
  • Expression drift. If jobs are user-editable, validate expressions with CronExpression::isValidExpression() before saving. Otherwise one bad row can break the whole tick loop depending on how the runner handles parse errors.
  • Overlap and drift. A * * * * * tick misses minutes during deploys or slow previous runs. Make the runner idempotent: select jobs where next_run <= now, advance next_run transactionally, don't store booleans like is_due.
  • Extension seams (if using the bundle). The manager service (add/remove), the tick command (execution), the entity (schema), and — as of 1.0.2 — the job-resolution/container step are the four places to subclass or decorate. Everything else is glue; don't bother.
  • Migration path off it. Started with the bundle and want out? Dump name/command/schedule/enabled, map schedule onto a cron column on a custom model, convert each stored command into a job class if you haven't already (1.0.2 pushes you in that direction anyway), and replace the tick with a single schedule:run-style loop. No data loss, no behavioral change — which is exactly why most Laravel teams skip the bundle and start here.
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.
unabomber/timezone
delatbabel/contacts
astritzeqiri/g-recaptcha
kevinongko/laravel-genode
developeruz/laravel-analytics
robbiep/afterthedeadline
frankkessler/incontact-laravel-oauth2-rest
jlxh/laravel-userlog
davidmgilo/timetables
qylinfly/role-permission
reflect-digital/conduit
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr