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

Crontask Laravel Package

frcho/crontask

frcho/crontask is a Laravel/PHP package for managing cron-based scheduled tasks. It helps you define, organize, and run recurring jobs from your application, keeping scheduling consistent and easier to maintain instead of scattering cron entries across servers.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and register. The package targets Symfony 4/5, so it lands via Composer and — unless the README explicitly says otherwise — needs manual bundle registration in config/bundles.php:

composer require frcho/crontask
// config/bundles.php
Frcho\CronTask\CronTaskBundle::class => ['all' => true],

Verify the actual namespace from vendor/frcho/crontask/composer.json (autoload.psr-4) before editing bundles.php — small packages often change namespace between releases, and the autoload prefix in the README can lag behind the code.

Where to look first. In this order:

  1. vendor/frcho/crontask/README.md — the canonical usage sample.
  2. vendor/frcho/crontask/src/Command/ — the console entry point. This tells you the real command name and its options; bin/console list after registration confirms it.
  3. vendor/frcho/crontask/DependencyInjection/Configuration.php — the config tree. This is the ground truth for what keys exist, not the README.

The first use case. The package exists to collapse a pile of crontab lines into one. Instead of:

*/5 * * * * php /var/www/app/bin/console app:sync-orders
0 3 * * *   php /var/www/app/bin/console app:prune-sessions

you register a single system cron entry that ticks the bundle every minute, and let the bundle decide what is due:

* * * * * cd /var/www/app && php bin/console <crontask:run-command> >> /var/log/app/crontask.log 2>&1

Declare one task wrapping app:sync-orders at */5 * * * * and another wrapping app:prune-sessions at 0 3 * * *. You now version-control your schedule alongside the code that it runs, and adding a task no longer requires SSH access to the production crontab.

Before wiring the system cron, run the command by hand in dev with -vvv and whatever dry-run flag the bundle exposes. Confirm it exits 0 and lists/executes the expected tasks. Only then hand it to cron.

Implementation Patterns

Wrap existing commands; do not rewrite them. The highest-value pattern is treating the bundle as a dispatcher in front of commands you already have. Your app:sync-orders keeps its own logic, arguments, and tests; the bundle only owns the when. This keeps you portable — if you later migrate to symfony/scheduler (6.3+) or cron/cron-bundle, the command classes survive untouched.

One task, one command. Resist packing multiple commands into a single scheduled task. Per-task scheduling gives you per-task logging, timing, and failure isolation. If two jobs must run in sequence and share state, model that as one command that internally does both, or use a lock/flag file.

Configure per environment. Put schedules in config/packages/crontask.yaml with an when@dev override that either disables everything or narrows it to a single harmless task. Nothing is worse than a developer's laptop silently pruning the shared staging database because the config was copied wholesale from production.

Make every task idempotent and lock-protected. Cron has no concept of "still running." If your tick interval is one minute and a task can take three, you will get overlapping executions. Two mitigations:

  • Use the bundle's overlap protection if it exposes one (check for a lock/withoutOverlapping-style option in Configuration.php).
  • Otherwise, wrap the task body in Symfony\Component\Lock\LockFactory and bail out early if the lock is held.

Push the schedule into code review. Because tasks live in YAML/PHP rather than a server's crontab, a schedule change is a diff, a PR, and a deploy. Encourage the team to treat timing changes with the same scrutiny as code changes — a typo in a cron expression is a silent, six-week outage.

Separate the tick from the work for slow jobs. For anything that can exceed a minute, have the scheduled task enqueue a Symfony Messenger message rather than do the work inline. The cron tick stays sub-second and predictable; retries and backoff come from Messenger rather than being hand-rolled.

Log structured output. Have each task emit a start line with task name and timestamp, and an end line with duration and exit code. When you are debugging "did it run at 3am," grepping a single append-only file beats reconstructing from syslog.

Test the schedule, not just the command. A cheap regression test: load the container, pull the configured task list, and assert the expected names/cron expressions are present. This catches the copy-paste error where app:prune-sessions accidentally keeps */5 * * * * from the task above it.

Gotchas and Tips

Check the maintenance and support horizon before committing. Five stars, zero dependents, and a description pinned to Symfony 4/5. That constraint is the real headline: if you are on Symfony 6/7, the composer.json require block probably blocks install, and if you are planning an upgrade, this dependency becomes a blocker. Weigh this against symfony/scheduler (first-party, 6.3+) or cron/cron-bundle. For a greenfield project on a modern Symfony, this package is hard to justify; for a Symfony 4/5 app with a working install, it is a perfectly reasonable way to get out of hand-edited crontabs today.

Timezone is almost certainly the bug. Cron expressions are evaluated in some timezone — server default, PHP default, or an explicit config key. date.timezone in php.ini, TZ in the cron environment, and the bundle's own config can all disagree. Set it explicitly, and verify by scheduling a task a few minutes out and watching the clock. A DST transition is the classic way to discover you got this wrong — a 0 2 * * * job either runs twice or not at all.

The cron environment is not your shell environment. System cron gives you a minimal PATH, no ~/.bashrc, and possibly a different PHP binary. Symptoms: works interactively, fails in cron with "command not found" or an unexpected PHP version. Fix by using absolute paths for both php and the project directory, and by sourcing the same env file your web process uses. Always redirect stdout and stderr (>> file 2>&1) or you will debug blind.

"Nothing happened" is usually cache or config. After changing schedules, run bin/console cache:clear — Symfony 4/5 caches the compiled container, and config-tree changes are not picked up until the container is rebuilt. On deploy, make sure your release process warms the cache before the cron tick starts firing against the new release directory.

Exit codes matter more than output. A task that fails but exits 0 is invisible to monitoring. If the bundle swallows exceptions to keep the tick alive (a common and defensible design for a scheduler), you lose the failure signal — so hook into its logging or an event/subscriber extension point and forward failures to your alerting channel. Check src/ for dispatched events or a TaskEvents-style class; that is your clean integration seam.

Do not run the tick as root, and do not run two ticks concurrently. The former is a security habit; the latter is a correctness one. If your deploy tooling restarts cron or you accidentally add the crontab line twice, two ticks will happily race each other. A flock-based wrapper around the system cron command is five seconds of work:

* * * * * flock -n /tmp/crontask.lock php /var/www/app/bin/console <crontask:run> >> /var/log/app/crontask.log 2>&1

Debugging sequence when a task will not fire: (1) run the bundle command manually with -vvv; (2) confirm the task appears in the bundle's list/inspect command; (3) check the cron expression against the current server time and timezone; (4) confirm the system crontab entry actually exists (crontab -l as the right user); (5) check var/log/ and /var/log/syslog for cron's own complaints. Skipping to step 5 wastes the most time.

Extension points worth probing before forking. Look for a task interface you can implement, an event dispatcher subscriber for pre/post execution, and a service you can decorate to override execution. Any of these lets you add metrics, alerting, or a kill switch without patching vendor/. Given the package's size, be prepared to fork — but decorate first and keep the fork as a last resort, since a fork of a five-star package is a fork you alone maintain.

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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
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
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core