The lock that blocks tomorrow's task
withoutOverlapping prevents two copies of the same task from running at once. Its cache lock expires after 24 hours by default. Laravel documents that an unexpected server problem can leave the lock stuck, requiring schedule:clear-cache.
Shorten the lock only when you know the maximum safe run time. Then send a heartbeat after the task finishes. The heartbeat detects both a stuck lock and any other path that prevents useful work from completing.
Add a success heartbeat
Use onSuccess() to report only after the scheduled command succeeds. Keep the heartbeat URL in an environment variable, not in source control. The example limits the lock to 30 minutes because the task should normally finish well inside that time.
# .env
POSTDEPLOY_HEARTBEAT_URL=https://ingest.postdeploy.dev/h/hb_YOUR_TOKEN
use Illuminate\Support\Facades\Schedule;
use Illuminate\Support\Facades\Http;
Schedule::command('reports:nightly')
->dailyAt('03:17')
->withoutOverlapping(30)
->onSuccess(function () {
Http::get(config('services.postdeploy.heartbeat_url'));
});
Test the scheduler and recovery
Run the scheduler manually and confirm a passing heartbeat. If a task stops running after a server problem, inspect its cache backend and clear only the Scheduler locks after you understand the impact.
php artisan schedule:run
php artisan schedule:list
php artisan schedule:clear-cache
Alert on a failed task sooner
A missing success heartbeat alerts after the monitor grace period. Add Laravel's failure handling for immediate application-level alerts when that suits the task. Keep the success heartbeat because it detects a task that did not start at all.
Questions
How long does Laravel withoutOverlapping lock a task?
It expires after 24 hours by default. Pass a minute value to withoutOverlapping when you know a shorter timeout is safe.
How do I clear a stuck Laravel schedule lock?
Laravel provides php artisan schedule:clear-cache. Use it when an unexpected server problem left a Scheduler lock stuck, after checking that another task instance is not still running.
What PostDeploy does not do here
- PostDeploy does not read Laravel cache locks
- PostDeploy does not run schedule:clear-cache
- PostDeploy does not execute Artisan commands on your server
Sources
Links are the platform's own documentation for the failure mode described above.