diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 7f0c767a..75c28a9b 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -23,21 +23,9 @@ jobs:
strategy:
fail-fast: true
matrix:
- php: [7.3, 7.4, '8.0', 8.1, 8.2, 8.3]
- laravel: [8, 9, 10, 11]
+ php: ['8.0', 8.1, 8.2, 8.3]
+ laravel: [9, 10, 11]
exclude:
- - php: 7.3
- laravel: 9
- - php: 7.3
- laravel: 10
- - php: 7.3
- laravel: 11
- - php: 7.4
- laravel: 9
- - php: 7.4
- laravel: 10
- - php: 7.4
- laravel: 11
- php: '8.0'
laravel: 10
- php: '8.0'
diff --git a/composer.json b/composer.json
index 91275675..8ce0634b 100644
--- a/composer.json
+++ b/composer.json
@@ -10,21 +10,21 @@
}
],
"require": {
- "php": "^7.3|^8.0",
+ "php": "^8.0",
"ext-json": "*",
"ext-pcntl": "*",
"ext-posix": "*",
- "illuminate/contracts": "^8.17|^9.0|^10.0|^11.0",
- "illuminate/queue": "^8.17|^9.0|^10.0|^11.0",
- "illuminate/support": "^8.17|^9.0|^10.0|^11.0",
+ "illuminate/contracts": "^9.21|^10.0|^11.0",
+ "illuminate/queue": "^9.21|^10.0|^11.0",
+ "illuminate/support": "^9.21|^10.0|^11.0",
"nesbot/carbon": "^2.17|^3.0",
"ramsey/uuid": "^4.0",
- "symfony/process": "^5.0|^6.0|^7.0",
- "symfony/error-handler": "^5.0|^6.0|^7.0"
+ "symfony/process": "^6.0|^7.0",
+ "symfony/error-handler": "^6.0|^7.0"
},
"require-dev": {
"mockery/mockery": "^1.0",
- "orchestra/testbench": "^6.0|^7.0|^8.0|^9.0",
+ "orchestra/testbench": "^7.0|^8.0|^9.0",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.0|^10.4",
"predis/predis": "^1.1|^2.0"
diff --git a/src/Console/ClearCommand.php b/src/Console/ClearCommand.php
index d3a7e9f5..a9ba8aa5 100644
--- a/src/Console/ClearCommand.php
+++ b/src/Console/ClearCommand.php
@@ -41,7 +41,7 @@ public function handle(JobRepository $jobRepository, QueueManager $manager)
}
if (! method_exists(RedisQueue::class, 'clear')) {
- $this->line('Clearing queues is not supported on this version of Laravel');
+ $this->components->error('Clearing queues is not supported on this version of Laravel.');
return 1;
}
@@ -54,7 +54,7 @@ public function handle(JobRepository $jobRepository, QueueManager $manager)
$count = $manager->connection($connection)->clear($queue);
- $this->line('Cleared '.$count.' jobs from the ['.$queue.'] queue ');
+ $this->components->info('Cleared '.$count.' jobs from the ['.$queue.'] queue.');
return 0;
}
diff --git a/src/Console/ClearMetricsCommand.php b/src/Console/ClearMetricsCommand.php
index 799c4c3b..35b503ac 100644
--- a/src/Console/ClearMetricsCommand.php
+++ b/src/Console/ClearMetricsCommand.php
@@ -31,6 +31,6 @@ public function handle(MetricsRepository $metrics)
{
$metrics->clear();
- $this->info('Metrics cleared successfully.');
+ $this->components->info('Metrics cleared successfully.');
}
}
diff --git a/src/Console/ContinueCommand.php b/src/Console/ContinueCommand.php
index 0cccc6b1..7a6050a3 100644
--- a/src/Console/ContinueCommand.php
+++ b/src/Console/ContinueCommand.php
@@ -36,12 +36,19 @@ public function handle(MasterSupervisorRepository $masters)
return Str::startsWith($master->name, MasterSupervisor::basename());
})->all();
- foreach (Arr::pluck($masters, 'pid') as $processId) {
- $this->info("Sending CONT Signal To Process: {$processId}");
+ collect(Arr::pluck($masters, 'pid'))
+ ->whenNotEmpty(fn () => $this->components->info('Sending CONT signal to processes.'))
+ ->whenEmpty(fn () => $this->components->info('No processes to continue.'))
+ ->each(function ($processId) {
+ $result = true;
- if (! posix_kill($processId, SIGCONT)) {
- $this->error("Failed to kill process: {$processId} (".posix_strerror(posix_get_last_error()).')');
- }
- }
+ $this->components->task("Process: $processId", function () use ($processId, &$result) {
+ return $result = posix_kill($processId, SIGCONT);
+ });
+
+ if (! $result) {
+ $this->components->error("Failed to kill process: {$processId} (".posix_strerror(posix_get_last_error()).')');
+ }
+ })->whenNotEmpty(fn () => $this->output->writeln(''));
}
}
diff --git a/src/Console/ContinueSupervisorCommand.php b/src/Console/ContinueSupervisorCommand.php
index 793bd6ad..c5643b3a 100644
--- a/src/Console/ContinueSupervisorCommand.php
+++ b/src/Console/ContinueSupervisorCommand.php
@@ -38,15 +38,15 @@ public function handle(SupervisorRepository $supervisors)
}))->pid;
if (is_null($processId)) {
- $this->error('Failed to find a supervisor with this name');
+ $this->components->error('Failed to find a supervisor with this name');
return 1;
}
- $this->info("Sending CONT Signal To Process: {$processId}");
+ $this->components->info("Sending CONT signal to process: {$processId}");
if (! posix_kill($processId, SIGCONT)) {
- $this->error("Failed to send CONT signal to process: {$processId} (".posix_strerror(posix_get_last_error()).')');
+ $this->components->error("Failed to send CONT signal to process: {$processId} (".posix_strerror(posix_get_last_error()).')');
}
}
}
diff --git a/src/Console/ForgetFailedCommand.php b/src/Console/ForgetFailedCommand.php
index 9ab3da15..20114f33 100644
--- a/src/Console/ForgetFailedCommand.php
+++ b/src/Console/ForgetFailedCommand.php
@@ -31,9 +31,9 @@ public function handle(JobRepository $repository)
$repository->deleteFailed($this->argument('id'));
if ($this->laravel['queue.failer']->forget($this->argument('id'))) {
- $this->info('Failed job deleted successfully!');
+ $this->components->info('Failed job deleted successfully!');
} else {
- $this->error('No failed job matches the given ID.');
+ $this->components->error('No failed job matches the given ID.');
return 1;
}
diff --git a/src/Console/HorizonCommand.php b/src/Console/HorizonCommand.php
index 581bdb77..36fcf1f9 100644
--- a/src/Console/HorizonCommand.php
+++ b/src/Console/HorizonCommand.php
@@ -32,7 +32,7 @@ class HorizonCommand extends Command
public function handle(MasterSupervisorRepository $masters)
{
if ($masters->find(MasterSupervisor::name())) {
- return $this->comment('A master supervisor is already running on this machine.');
+ return $this->components->warn('A master supervisor is already running on this machine.');
}
$environment = $this->option('environment') ?? config('horizon.env') ?? config('app.env');
@@ -43,12 +43,14 @@ public function handle(MasterSupervisorRepository $masters)
ProvisioningPlan::get(MasterSupervisor::name())->deploy($environment);
- $this->info('Horizon started successfully.');
+ $this->components->info('Horizon started successfully.');
pcntl_async_signals(true);
pcntl_signal(SIGINT, function () use ($master) {
- $this->line('Shutting down...');
+ $this->output->writeln('');
+
+ $this->components->info('Shutting down.');
return $master->terminate();
});
diff --git a/src/Console/InstallCommand.php b/src/Console/InstallCommand.php
index 422ba1fe..67f0926c 100644
--- a/src/Console/InstallCommand.php
+++ b/src/Console/InstallCommand.php
@@ -29,18 +29,17 @@ class InstallCommand extends Command
*/
public function handle()
{
- $this->comment('Publishing Horizon Service Provider...');
- $this->callSilent('vendor:publish', ['--tag' => 'horizon-provider']);
+ $this->components->info('Installing Horizon resources.');
- $this->comment('Publishing Horizon Assets...');
- $this->callSilent('vendor:publish', ['--tag' => 'horizon-assets']);
-
- $this->comment('Publishing Horizon Configuration...');
- $this->callSilent('vendor:publish', ['--tag' => 'horizon-config']);
+ collect([
+ 'Assets' => fn () => $this->callSilent('vendor:publish', ['--tag' => 'horizon-assets']) == 0,
+ 'Service Provider' => fn () => $this->callSilent('vendor:publish', ['--tag' => 'horizon-provider']) == 0,
+ 'Configuration' => fn () => $this->callSilent('vendor:publish', ['--tag' => 'horizon-config']) == 0,
+ ])->each(fn ($task, $description) => $this->components->task($description, $task));
$this->registerHorizonServiceProvider();
- $this->info('Horizon scaffolding installed successfully.');
+ $this->components->info('Horizon scaffolding installed successfully.');
}
/**
diff --git a/src/Console/ListCommand.php b/src/Console/ListCommand.php
index 80f7ccd2..41a0f2b3 100644
--- a/src/Console/ListCommand.php
+++ b/src/Console/ListCommand.php
@@ -32,9 +32,11 @@ public function handle(MasterSupervisorRepository $masters)
$masters = $masters->all();
if (empty($masters)) {
- return $this->info('No machines are running.');
+ return $this->components->info('No machines are running.');
}
+ $this->output->writeln('');
+
$this->table([
'Name', 'PID', 'Supervisors', 'Status',
], collect($masters)->map(function ($master) {
@@ -47,5 +49,7 @@ public function handle(MasterSupervisorRepository $masters)
$master->status,
];
})->all());
+
+ $this->output->writeln('');
}
}
diff --git a/src/Console/PauseCommand.php b/src/Console/PauseCommand.php
index 1260d5ad..7b253afc 100644
--- a/src/Console/PauseCommand.php
+++ b/src/Console/PauseCommand.php
@@ -36,12 +36,19 @@ public function handle(MasterSupervisorRepository $masters)
return Str::startsWith($master->name, MasterSupervisor::basename());
})->all();
- foreach (Arr::pluck($masters, 'pid') as $processId) {
- $this->info("Sending USR2 Signal To Process: {$processId}");
+ collect(Arr::pluck($masters, 'pid'))
+ ->whenNotEmpty(fn () => $this->components->info('Sending USR2 signal to processes.'))
+ ->whenEmpty(fn () => $this->components->info('No processes to pause.'))
+ ->each(function ($processId) {
+ $result = true;
- if (! posix_kill($processId, SIGUSR2)) {
- $this->error("Failed to kill process: {$processId} (".posix_strerror(posix_get_last_error()).')');
- }
- }
+ $this->components->task("Process: $processId", function () use ($processId, &$result) {
+ return $result = posix_kill($processId, SIGUSR2);
+ });
+
+ if (! $result) {
+ $this->components->error("Failed to kill process: {$processId} (".posix_strerror(posix_get_last_error()).')');
+ }
+ })->whenNotEmpty(fn () => $this->output->writeln(''));
}
}
diff --git a/src/Console/PauseSupervisorCommand.php b/src/Console/PauseSupervisorCommand.php
index c03e0c2c..ef9811a8 100644
--- a/src/Console/PauseSupervisorCommand.php
+++ b/src/Console/PauseSupervisorCommand.php
@@ -38,15 +38,15 @@ public function handle(SupervisorRepository $supervisors)
}))->pid;
if (is_null($processId)) {
- $this->error('Failed to find a supervisor with this name');
+ $this->components->error('Failed to find a supervisor with this name');
return 1;
}
- $this->info("Sending USR2 Signal To Process: {$processId}");
+ $this->components->info("Sending USR2 signal to process: {$processId}");
if (! posix_kill($processId, SIGUSR2)) {
- $this->error("Failed to send USR2 signal to process: {$processId} (".posix_strerror(posix_get_last_error()).')');
+ $this->components->error("Failed to send USR2 signal to process: {$processId} (".posix_strerror(posix_get_last_error()).')');
}
}
}
diff --git a/src/Console/PurgeCommand.php b/src/Console/PurgeCommand.php
index d97ee144..16070d5c 100644
--- a/src/Console/PurgeCommand.php
+++ b/src/Console/PurgeCommand.php
@@ -96,13 +96,15 @@ public function purge($master, $signal = SIGTERM)
$master, $this->supervisors->longestActiveTimeout()
);
- collect($expired)->each(function ($processId) use ($master, $signal) {
- $this->comment("Killing Process: {$processId}");
-
- exec("kill -s {$signal} {$processId}");
-
- $this->processes->forgetOrphans($master, [$processId]);
- });
+ collect($expired)
+ ->whenNotEmpty(fn () => $this->components->info('Sending TERM signal to expired processes of ['.$master.']'))
+ ->each(function ($processId) use ($master, $signal) {
+ $this->components->task("Process: $processId", function () use ($processId, $signal) {
+ exec("kill -s {$signal} {$processId}");
+ });
+
+ $this->processes->forgetOrphans($master, [$processId]);
+ })->whenNotEmpty(fn () => $this->output->writeln(''));
}
/**
@@ -118,12 +120,18 @@ protected function recordOrphans($master, $signal)
$master, $orphans = $this->inspector->orphaned()
);
- foreach ($orphans as $processId) {
- $this->info("Observed Orphan: {$processId}");
+ collect($orphans)
+ ->whenNotEmpty(fn () => $this->components->info('Sending TERM signal to orphaned processes of ['.$master.']'))
+ ->each(function ($processId) use ($signal) {
+ $result = true;
- if (! posix_kill($processId, $signal)) {
- $this->error("Failed to kill process for Orphan: {$processId} (".posix_strerror(posix_get_last_error()).')');
- }
- }
+ $this->components->task("Process: $processId", function () use ($processId, $signal, &$result) {
+ return $result = posix_kill($processId, $signal);
+ });
+
+ if (! $result) {
+ $this->components->error("Failed to kill orphan process: {$processId} (".posix_strerror(posix_get_last_error()).')');
+ }
+ })->whenNotEmpty(fn () => $this->output->writeln(''));
}
}
diff --git a/src/Console/SnapshotCommand.php b/src/Console/SnapshotCommand.php
index 5db99336..3718b371 100644
--- a/src/Console/SnapshotCommand.php
+++ b/src/Console/SnapshotCommand.php
@@ -34,7 +34,7 @@ public function handle(Lock $lock, MetricsRepository $metrics)
if ($lock->get('metrics:snapshot', config('horizon.metrics.snapshot_lock', 300) - 30)) {
$metrics->snapshot();
- $this->info('Metrics snapshot stored successfully.');
+ $this->components->info('Metrics snapshot stored successfully.');
}
}
}
diff --git a/src/Console/StatusCommand.php b/src/Console/StatusCommand.php
index 5698c49c..ba47910a 100644
--- a/src/Console/StatusCommand.php
+++ b/src/Console/StatusCommand.php
@@ -30,7 +30,7 @@ class StatusCommand extends Command
public function handle(MasterSupervisorRepository $masterSupervisorRepository)
{
if (! $masters = $masterSupervisorRepository->all()) {
- $this->error('Horizon is inactive.');
+ $this->components->error('Horizon is inactive.');
return 1;
}
@@ -38,12 +38,12 @@ public function handle(MasterSupervisorRepository $masterSupervisorRepository)
if (collect($masters)->contains(function ($master) {
return $master->status === 'paused';
})) {
- $this->warn('Horizon is paused.');
+ $this->components->warn('Horizon is paused.');
return 1;
}
- $this->info('Horizon is running.');
+ $this->components->info('Horizon is running.');
return 0;
}
diff --git a/src/Console/SupervisorCommand.php b/src/Console/SupervisorCommand.php
index aeb4773e..a4856c6c 100644
--- a/src/Console/SupervisorCommand.php
+++ b/src/Console/SupervisorCommand.php
@@ -68,7 +68,7 @@ public function handle(SupervisorFactory $factory)
try {
$supervisor->ensureNoDuplicateSupervisors();
} catch (Exception $e) {
- $this->error('A supervisor with this name is already running.');
+ $this->components->error('A supervisor with this name is already running.');
return 13;
}
diff --git a/src/Console/SupervisorsCommand.php b/src/Console/SupervisorsCommand.php
index 693dde07..4272646f 100644
--- a/src/Console/SupervisorsCommand.php
+++ b/src/Console/SupervisorsCommand.php
@@ -32,9 +32,11 @@ public function handle(SupervisorRepository $supervisors)
$supervisors = $supervisors->all();
if (empty($supervisors)) {
- return $this->info('No supervisors are running.');
+ return $this->components->info('No supervisors are running.');
}
+ $this->output->writeln('');
+
$this->table([
'Name', 'PID', 'Status', 'Workers', 'Balancing',
], collect($supervisors)->map(function ($supervisor) {
@@ -48,5 +50,7 @@ public function handle(SupervisorRepository $supervisors)
$supervisor->options['balance'],
];
})->all());
+
+ $this->output->writeln('');
}
}
diff --git a/src/Console/TerminateCommand.php b/src/Console/TerminateCommand.php
index a45cf8a1..c0d8d476 100644
--- a/src/Console/TerminateCommand.php
+++ b/src/Console/TerminateCommand.php
@@ -48,13 +48,20 @@ public function handle(CacheFactory $cache, MasterSupervisorRepository $masters)
return Str::startsWith($master->name, MasterSupervisor::basename());
})->all();
- foreach (Arr::pluck($masters, 'pid') as $processId) {
- $this->info("Sending TERM Signal To Process: {$processId}");
+ collect(Arr::pluck($masters, 'pid'))
+ ->whenNotEmpty(fn () => $this->components->info('Sending TERM signal to processes.'))
+ ->whenEmpty(fn () => $this->components->info('No processes to terminate.'))
+ ->each(function ($processId) {
+ $result = true;
- if (! posix_kill($processId, SIGTERM)) {
- $this->error("Failed to kill process: {$processId} (".posix_strerror(posix_get_last_error()).')');
- }
- }
+ $this->components->task("Process: $processId", function () use ($processId, &$result) {
+ return $result = posix_kill($processId, SIGTERM);
+ });
+
+ if (! $result) {
+ $this->components->error("Failed to kill process: {$processId} (".posix_strerror(posix_get_last_error()).')');
+ }
+ })->whenNotEmpty(fn () => $this->output->writeln(''));
$this->laravel['cache']->forever('illuminate:queue:restart', $this->currentTime());
}
diff --git a/src/Console/TimeoutCommand.php b/src/Console/TimeoutCommand.php
index 2dd74fb2..f9173d47 100644
--- a/src/Console/TimeoutCommand.php
+++ b/src/Console/TimeoutCommand.php
@@ -38,6 +38,10 @@ public function handle()
{
$plan = ProvisioningPlan::get(MasterSupervisor::name())->plan;
- $this->line(collect($plan[$this->argument('environment')] ?? [])->max('timeout') ?? 60);
+ $environment = $this->argument('environment');
+
+ $timeout = collect($plan[$this->argument('environment')] ?? [])->max('timeout') ?? 60;
+
+ $this->components->info('Maximum timeout for '.$environment.' environment: '.$timeout.' seconds.');
}
}
diff --git a/src/ProcessPool.php b/src/ProcessPool.php
index a9c43c48..2f07cec6 100644
--- a/src/ProcessPool.php
+++ b/src/ProcessPool.php
@@ -270,7 +270,7 @@ protected function stopTerminatingProcessesThatAreHanging()
foreach ($this->terminatingProcesses as $process) {
$timeout = $this->options->timeout;
- if ($process['terminatedAt']->addSeconds($timeout)->lte(CarbonImmutable::now())) {
+ if ($process['terminatedAt']->addSeconds((int) $timeout)->lte(CarbonImmutable::now())) {
$process['process']->stop();
}
}