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

Command Scheduler Laravel Package

t-labs-co/command-scheduler

t-labs-co/command-scheduler is a Laravel package for scheduling and managing Artisan and console commands. Define command schedules in code, control timing and recurrence, and keep routine tasks organized without complex cron setup. Simple APIs help you register, run, and monitor scheduled commands.

View on GitHub
Deep Wiki
Context7

Getting Started

v1.0.0 is the first tagged release, which matters more than the (empty) changelog suggests: the public API is now what you're expected to build against, and from here on you can rely on semver for upgrades. The release notes contain no migration steps, deprecations, or feature list — just a link to the commit history — so treat this as a "read the source before you trust it" package rather than a documented one.

Minimal path to first value:

  1. composer require t-labs-co/command-scheduler and confirm the service provider is auto-discovered (php artisan about or php artisan vendor:publish --provider=...). If discovery is off, register it manually in bootstrap/providers.php (Laravel 11+) or config/app.php.
  2. Publish and read the config file first — before writing any scheduling code. For a scheduler package the config is where the real decisions live (default queue/connection, overlap and mutex behaviour, logging channel, timezone).
  3. Read src/ top to bottom. It's a v1.0.0 with one commit-linked changelog; the README is likely the only prose you get, so the provider's register()/boot() and the main facade/entry class are your actual documentation.
  4. First use case: take one existing $schedule->command(...) line out of routes/console.php / app/Console/Kernel.php and express it through the package instead. One command, one schedule entry, run it manually with php artisan schedule:run and watch what it does to the log. Only after that works should you port the rest.

If the package's value proposition (queueing commands, dynamic/DB-driven schedules, per-run bookkeeping) doesn't match what you see in src/, stop here — v1.0.0 is cheap to back out of, and far more expensive to unwind after you've migrated forty schedule entries.

Implementation Patterns

Centralise the schedule definition. The main win of a package like this is getting scheduling logic out of Kernel.php/routes/console.php and into something testable. Keep a single registry (a config array, a DB table, or a dedicated class) as the source of truth, and let the package's bootstrapping read from it. Anything you'd otherwise hardcode in the kernel should live there.

Wrap existing commands rather than rewriting them. Schedule through the package but keep the command classes plain Laravel commands. That way the package is a thin scheduling layer you can remove, not a framework your commands are welded to. If the package requires extending a base command class, isolate those in one namespace so the blast radius is visible.

Guard against overlap and concurrency explicitly. Whatever the package offers for withoutOverlapping() / onOneServer() semantics, set it deliberately per task. For a package whose selling point is scheduling, the failure mode you'll actually hit in production is a task piling up on itself — and if the package manages its own mutex, it may not respect the framework's. Verify with two workers.

Test the schedule, not the scheduler. Assert on whatever structure the package exposes (the resolved list of due tasks, a task registry, a value object per entry) rather than sleeping and invoking schedule:run. Use Carbon::setTestNow() and travel in time. If nothing is inspectable, that's a design smell worth raising upstream.

Integration with the rest of the stack: point the package's log channel at a dedicated channel so scheduled-run output doesn't pollute application logs; route jobs to a named queue so a runaway schedule can't starve user-facing work; and if it dispatches jobs rather than commands, make sure your queue worker's --timeout is comfortably above your longest scheduled task.

Rollout pattern for a schedule-heavy app: migrate one low-risk task, run it in parallel with the existing entry (different log channel, output compared), then delete the old one. This package has no upgrade history to learn from — you're establishing the baseline.

Gotchas and Tips

  • The changelog is a link, not a changelog. "Full Changelog: .../commits/v1.0.0" tells you nothing about intent, known issues, or what was deliberately left out. Budget an hour to read the commit messages before adopting. If they're squash-merged "wip" commits, downgrade your confidence accordingly.
  • v1.0.0 is a promise, not a track record. A 1.0 tag with no prior assessments means no one has documented what breaks. Pin the version ("t-labs-co/command-scheduler": "^1.0" is fine, but don't float to *) and read the diff on every minor bump.
  • Timezone drift. Scheduler bugs are almost always timezone bugs. Check whether the package applies config('app.timezone'), a package-level timezone, or the server's. Set it explicitly and assert it in a test.
  • Mutex/overlap ownership is the classic trap. If the package maintains its own lock store (cache, DB table), it won't share state with Laravel's withoutOverlapping(). Two entries for the same logical task can then run simultaneously. Pick one mechanism and use it everywhere.
  • Silent failures. Schedulers fail quietly by default. Whatever the package's error handling is, wire failed runs to something loud — a log channel with alerting, or a failed event listener. Test by deliberately throwing inside a scheduled command.
  • Debugging: php artisan schedule:list reflects Laravel's kernel, not necessarily the package's registry — don't assume they agree. Cross-check with the package's own inspection command if one exists, and fall back to schedule:run -v plus a temporary Log::info() in the package's dispatch path.
  • Extension points: the service provider and config are the two sanctioned seams. Prefer binding an interface or overriding config over subclassing internals — with no documented extension API at v1.0.0, anything you subclass is fair game to change in 1.1.
  • Escape hatch: keep the ability to run the same tasks via plain $schedule->command() behind a flag. If the package stalls (no releases, no response to issues), switching back should be a config change, not a rewrite.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin