Skip to main content

Cloudsoft Zone Build, deploy and scale with practical guides to PHP, Node.js, React, DevOps and AI automation. Explore the guides

Cloudsoft Zone
DevOpsLaravelPHPTroubleshooting guide

Laravel scheduler not running: trace cron, task filters and execution

Diagnose a Laravel scheduler not running by separating cron invocation, runtime configuration, due-task filters, cache locks and the task’s final effect.

Cloudsoft Zone

6 min read

Laravel product artwork with a scheduler troubleshooting path from cron invocation to task eligibility and completion.
Image: Cloudsoft Zone layout; Laravel / Public domain
In this article

The daily report did not arrive, so you add another cron entry. Tomorrow two reports arrive, but the original failure remains unexplained. A missed scheduled task needs an execution trace, not another scheduler process.

When investigating a Laravel scheduler not running, separate three questions: did the host invoke the scheduler, did the task qualify to run, and did the task complete its intended effect? This guide follows that sequence for a Linux VPS using cron. Containers and managed schedulers have different invocation owners, but the same boundary checks apply.

Use read-only checks first and a harmless probe when execution evidence is missing. Do not manually replay billing, payment or bulk-mail commands while diagnosing cron. Our Laravel production checklist provides the surrounding deployment context.

Scheduler troubleshooting identifies missing host invocation, missing eligible task or a missing downstream effect.
An empty queue is not evidence that the host cron daemon failed.

Step 1: Write down the expected task and timestamp

Record the command or queued job, expected occurrence, task time zone and application environment. Also record the release directory and the account that owns scheduled execution. “The scheduler stopped” is too broad; “the report task due at 08:00 site time has no start record” is actionable.

Look for a start event, an exit outcome and the expected result. A missing email can be a mail-delivery problem even when the task completed. A dispatched job can wait behind other work. Avoid inferring scheduler failure from the final symptom alone.

Evidence missing First boundary to inspect
No cron invocation record Host cron, identity and executable path
Invocation exists but task never starts Task registration, due time and filters
Task starts but queued job waits Connection, queue and worker ownership
Job succeeds but report is absent Application effect and downstream service

Step 2: Inspect the actual cron owner

A user's crontab and a system cron file have different formats. A user crontab contains five time fields followed by the command. A file under /etc/cron.d includes a user field before the command. Copying the wrong format can make an apparently correct entry unusable.

Shell
sudo crontab -u app-runtime -l
systemctl is-active cron
sudo journalctl -u cron --since '30 minutes ago' --no-pager

Replace app-runtime with the actual application account. Journal availability depends on the host's logging setup; some installations record cron events in syslog. Absence from one log destination is not proof of absence from every destination.

Keep one production scheduler owner. Search the app's deployment configuration for an old user crontab, a system cron file, a container scheduler or a foreground scheduler process before adding anything. Duplicate owners can create intermittent behavior that disappears when you observe only one process.

Step 3: Check the CLI runtime and working directory

Cron does not inherit your interactive shell setup. Use an absolute PHP path and explicitly change into the current application directory. Verify the selected PHP runtime under the cron identity:

Shell
sudo -u app-runtime /usr/bin/php -v
sudo -u app-runtime /usr/bin/php --ini
sudo -u app-runtime sh -c 'cd /srv/example-app/current && /usr/bin/php artisan schedule:list'

Inspect only the diagnostic output needed; do not print the application's full configuration. CLI PHP can load different extensions or settings from PHP-FPM. A scheduler bootstrap failure may therefore coexist with a healthy website.

A conventional user-crontab entry looks like this:

cron
* * * * * cd /srv/example-app/current && /usr/bin/php artisan schedule:run >> /srv/example-app/shared/storage/logs/scheduler.log 2>&1

The log directory must exist and be writable only by the required accounts, with rotation and retention configured. During diagnosis, preserving output is more useful than discarding everything to the null device. The command uses the active release pointer so later deployments do not leave cron running an old checkout.

Step 4: Confirm the task is registered and due

Run schedule:list from the actual release. If your task is absent, inspect its registration and any conditional loading. Newer Laravel applications commonly define schedules in routes/console.php or through the application's schedule configuration.

Compare the next execution time with the configured task time zone. The host clock, application's default time zone and a task-specific time zone are different settings. A daylight-saving transition can affect local-clock schedules; design sensitive business events with explicit occurrence records.

Do not expect an hourly or daily task to execute every time you run schedule:run manually. It evaluates which tasks are due at that time. A successful command reporting no eligible tasks can be entirely correct.

A Laravel scheduled task must satisfy time and environment conditions, operating-state rules and locks or predicates.
Check the expected policy before removing a lock or enabling a paused task.

Step 5: Inspect filters, pause state and maintenance

Review environment restrictions, conditional predicates and whether the application is in maintenance mode. A intentionally paused scheduler should not be resumed simply because a task is missing. Establish who paused it and why.

Laravel 13's documented scheduler pause and continue controls are operating-state changes. Use them only when the recorded maintenance or incident policy permits resumption. Do not add exceptions such as execution during maintenance just to bypass an unexplained skip.

For overlap prevention, check whether the previous occurrence is legitimately still running. A long task can make the next occurrence skip as designed. For one-server execution, verify that all replicas use the same supported central cache and compatible task identity.

Never flush the entire Redis database to resolve a scheduler lock. It may hold queues, sessions and other application state. If a scheduler-specific lock is stale, confirm no live task owns it before using the documented scheduler lock-clear command. Record the action and verify the next controlled occurrence.

Step 6: Introduce a harmless temporary probe

In a reviewed staging reproduction or a controlled diagnostic change, add a log-only task with no customer effect:

PHP
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schedule;

Schedule::call(function () {
    Log::info('scheduler_probe', [
        'recorded_at' => now()->toIso8601String(),
    ]);
})->name('scheduler-probe')->everyMinute();

Use the application's normal logger and protected retention policy. Observe one or two expected ticks, then remove the probe. Do not confuse this invocation evidence with proof that the original business task completes.

If the probe runs but the report does not, the cron boundary is established. Move to the report's eligibility and execution rather than editing cron again. If the probe fails to bootstrap under cron, compare the runtime identity, current directory and configuration cache.

A harmless log-only scheduler probe establishes invocation evidence before tracing a dispatched job and its business effect.
Do not run a payment or bulk-email task just to prove scheduler connectivity.

Step 7: Follow background work to completion

Scheduled work may dispatch a queued job. Record its connection and queue name, then confirm the relevant worker is consuming them. Use a non-sensitive correlation identifier to connect the schedule occurrence, job attempt and final result.

Investigate worker pause, failure records, dependency latency and retry policy independently. A scheduler invocation can succeed immediately while the queued job remains unprocessed. Re-running the scheduler may dispatch duplicate work and worsen the backlog.

Step 8: Verify the fix and deployment behavior

Change one cause at a time. After correcting the cron path, user or task filter, observe the next expected occurrence under the normal owner. Confirm the harmless probe, the real task and its intended result separately.

If the application schedules sub-minute tasks, its scheduler invocation can remain active through the minute. Include the documented scheduler-interruption step after a completed deployment so an old invocation does not continue using old code. That is different from killing arbitrary PHP processes.

Record the root cause, corrected setting and next due time. Keep an alert for missing expected task completion, with an explicit owner. A cron daemon being active is not a meaningful completion alert by itself.

For the wider runtime checks, use our Laravel deployment checklist. For an application-specific scheduler and worker review, contact Cloudsoft Zone.

Featured image: Cloudsoft Zone technical layout with laravel artwork by Laravel (Public domain). Product mark resized proportionally for identification; no endorsement implied. Layout: CC BY-SA 4.0.

Frequently asked questions

  • Why does schedule:run say no tasks are ready?

    The scheduler can be working correctly while no task is due. Inspect schedule:list, time zones, task filters, maintenance or pause state and cache locks.

  • Should I run schedule:work and cron together?

    Use one documented scheduler owner for a deployment. Multiple invocations can duplicate work unless the relevant task coordination is correctly designed.

  • Can schedule:clear-cache fix every missed task?

    No. It addresses scheduler cache locks. Verify that no legitimate task is active and diagnose the specific lock before clearing it.

Advertise on CloudSoftZone

Your next customer could start right here.

Introduce your tool, product or business to readers exploring technology.

Advertise with us

Explore placements and request a private quote

Sources

  1. Laravel task scheduling — Laravel
  2. Ubuntu cron file syntax — Ubuntu
  3. Ubuntu cron daemon — Ubuntu
  4. PHP command-line options — PHP
  5. Laravel logging — Laravel
  6. Laravel atomic cache locks — Laravel

Comments

No comments yet. Be the first to join the conversation.

Leave a comment

Every comment is read by a moderator before it appears. Your email address is never published; it is used only to contact you about this comment.

Never published. Used only to contact you about this comment.

Loading the security check…

Comments are moderated before publication.