ScheduleRunCommand.php
TLDR
This file, ScheduleRunCommand.php
, is a part of the Illuminate\Console\Scheduling
namespace in the Laravel framework. It contains the ScheduleRunCommand
class, which is a command-line interface command used to run scheduled commands. It handles the execution of scheduled events based on their defined schedules.
Methods
handle
This method executes the console command. It takes in a Schedule
instance, a Dispatcher
instance, a Cache
instance, and an ExceptionHandler
instance as its parameters. It retrieves the due scheduled events from the Schedule
instance and iterates through them. It then checks if the events should be skipped based on any defined filters. If an event should be run on a single server, it delegates the execution to the runSingleServerEvent
method. Otherwise, it executes the event using the runEvent
method. Lastly, it repeats any repeatable events and displays a message if no scheduled commands are ready to run.
runSingleServerEvent
This method runs a single server event. It takes in an Event
instance as its parameter. It checks whether the event should be run on the current server based on its schedule start time. If it should be run, it executes the event using the runEvent
method. Otherwise, it displays a message indicating that the event has already run on another server.
runEvent
This method runs a given event. It takes in an Event
instance as its parameter. It extracts the command and description from the event and runs it using the components->task
method. It dispatches events for the starting, finishing, and failure of the scheduled task. If the event is not an instance of CallbackEvent
, it adds the event summary to a bullet list.
repeatEvents
This method runs the given repeating events. It takes in a collection of Event
instances as its parameter. It iterates through the events and checks if the schedule run should be interrupted. If so, it returns. If an event should repeat based on its schedule, it checks if the application is in maintenance mode and if the event passes any filters. If the event should run on a single server, it delegates the execution to the runSingleServerEvent
method. Otherwise, it executes the event using the runEvent
method. This process continues until the current time is past the start time of the scheduler command.
shouldInterrupt
This method determines if the schedule run should be interrupted. It checks if a specific cache value is set to true
.
clearInterruptSignal
This method ensures that the interrupt signal is cleared. It removes the specific cache value.
Classes
There are no classes defined in this file.
<?php
namespace Illuminate\Console\Scheduling;
use Illuminate\Console\Application;
use Illuminate\Console\Command;
use Illuminate\Console\Events\ScheduledTaskFailed;
use Illuminate\Console\Events\ScheduledTaskFinished;
use Illuminate\Console\Events\ScheduledTaskSkipped;
use Illuminate\Console\Events\ScheduledTaskStarting;
use Illuminate\Contracts\Cache\Repository as Cache;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\Sleep;
use Symfony\Component\Console\Attribute\AsCommand;
use Throwable;
#[AsCommand(name: 'schedule:run')]
class ScheduleRunCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'schedule:run';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Run the scheduled commands';
/**
* The schedule instance.
*
* @var \Illuminate\Console\Scheduling\Schedule
*/
protected $schedule;
/**
* The 24 hour timestamp this scheduler command started running.
*
* @var \Illuminate\Support\Carbon
*/
protected $startedAt;
/**
* Check if any events ran.
*
* @var bool
*/
protected $eventsRan = false;
/**
* The event dispatcher.
*
* @var \Illuminate\Contracts\Events\Dispatcher
*/
protected $dispatcher;
/**
* The exception handler.
*
* @var \Illuminate\Contracts\Debug\ExceptionHandler
*/
protected $handler;
/**
* The cache store implementation.
*
* @var \Illuminate\Contracts\Cache\Repository
*/
protected $cache;
/**
* The PHP binary used by the command.
*
* @var string
*/
protected $phpBinary;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
$this->startedAt = Date::now();
parent::__construct();
}
/**
* Execute the console command.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @param \Illuminate\Contracts\Events\Dispatcher $dispatcher
* @param \Illuminate\Contracts\Cache\Repository $cache
* @param \Illuminate\Contracts\Debug\ExceptionHandler $handler
* @return void
*/
public function handle(Schedule $schedule, Dispatcher $dispatcher, Cache $cache, ExceptionHandler $handler)
{
$this->schedule = $schedule;
$this->dispatcher = $dispatcher;
$this->cache = $cache;
$this->handler = $handler;
$this->phpBinary = Application::phpBinary();
$this->clearInterruptSignal();
$this->newLine();
$events = $this->schedule->dueEvents($this->laravel);
foreach ($events as $event) {
if (! $event->filtersPass($this->laravel)) {
$this->dispatcher->dispatch(new ScheduledTaskSkipped($event));
continue;
}
if ($event->onOneServer) {
$this->runSingleServerEvent($event);
} else {
$this->runEvent($event);
}
$this->eventsRan = true;
}
if ($events->contains->isRepeatable()) {
$this->repeatEvents($events->filter->isRepeatable());
}
if (! $this->eventsRan) {
$this->components->info('No scheduled commands are ready to run.');
} else {
$this->newLine();
}
}
/**
* Run the given single server event.
*
* @param \Illuminate\Console\Scheduling\Event $event
* @return void
*/
protected function runSingleServerEvent($event)
{
if ($this->schedule->serverShouldRun($event, $this->startedAt)) {
$this->runEvent($event);
} else {
$this->components->info(sprintf(
'Skipping [%s], as command already run on another server.', $event->getSummaryForDisplay()
));
}
}
/**
* Run the given event.
*
* @param \Illuminate\Console\Scheduling\Event $event
* @return void
*/
protected function runEvent($event)
{
$summary = $event->getSummaryForDisplay();
$command = $event instanceof CallbackEvent
? $summary
: trim(str_replace($this->phpBinary, '', $event->command));
$description = sprintf(
'<fg=gray>%s</> Running [%s]%s',
Carbon::now()->format('Y-m-d H:i:s'),
$command,
$event->runInBackground ? ' in background' : '',
);
$this->components->task($description, function () use ($event) {
$this->dispatcher->dispatch(new ScheduledTaskStarting($event));
$start = microtime(true);
try {
$event->run($this->laravel);
$this->dispatcher->dispatch(new ScheduledTaskFinished(
$event,
round(microtime(true) - $start, 2)
));
$this->eventsRan = true;
} catch (Throwable $e) {
$this->dispatcher->dispatch(new ScheduledTaskFailed($event, $e));
$this->handler->report($e);
}
return $event->exitCode == 0;
});
if (! $event instanceof CallbackEvent) {
$this->components->bulletList([
$event->getSummaryForDisplay(),
]);
}
}
/**
* Run the given repeating events.
*
* @param \Illuminate\Support\Collection<\Illuminate\Console\Scheduling\Event> $events
* @return void
*/
protected function repeatEvents($events)
{
$hasEnteredMaintenanceMode = false;
while (Date::now()->lte($this->startedAt->endOfMinute())) {
foreach ($events as $event) {
if ($this->shouldInterrupt()) {
return;
}
if (! $event->shouldRepeatNow()) {
continue;
}
$hasEnteredMaintenanceMode = $hasEnteredMaintenanceMode || $this->laravel->isDownForMaintenance();
if ($hasEnteredMaintenanceMode && ! $event->runsInMaintenanceMode()) {
continue;
}
if (! $event->filtersPass($this->laravel)) {
$this->dispatcher->dispatch(new ScheduledTaskSkipped($event));
continue;
}
if ($event->onOneServer) {
$this->runSingleServerEvent($event);
} else {
$this->runEvent($event);
}
$this->eventsRan = true;
}
Sleep::usleep(100000);
}
}
/**
* Determine if the schedule run should be interrupted.
*
* @return bool
*/
protected function shouldInterrupt()
{
return $this->cache->get('illuminate:schedule:interrupt', false);
}
/**
* Ensure the interrupt signal is cleared.
*
* @return bool
*/
protected function clearInterruptSignal()
{
$this->cache->forget('illuminate:schedule:interrupt');
}
}