fix: horizon job checker

This commit is contained in:
Andras Bacsai
2025-01-10 18:27:48 +01:00
parent a3648901ed
commit 02400added
9 changed files with 87 additions and 34 deletions

View File

@@ -2,6 +2,7 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\Enums\ApplicationDeploymentStatus;
use App\Models\ApplicationDeploymentQueue; use App\Models\ApplicationDeploymentQueue;
use App\Repositories\CustomJobRepository; use App\Repositories\CustomJobRepository;
use Illuminate\Console\Command; use Illuminate\Console\Command;
@@ -13,24 +14,31 @@ use Laravel\Horizon\Repositories\RedisJobRepository;
use function Laravel\Prompts\multiselect; use function Laravel\Prompts\multiselect;
use function Laravel\Prompts\select; use function Laravel\Prompts\select;
use function Laravel\Prompts\table; use function Laravel\Prompts\table;
use function Laravel\Prompts\text;
class HorizonManage extends Command class HorizonManage extends Command
{ {
protected $signature = 'horizon:manage {--can-i-restart-this-worker}'; protected $signature = 'horizon:manage {--can-i-restart-this-worker} {--job-status=}';
protected $description = 'Manage horizon'; protected $description = 'Manage horizon';
public function handle() public function handle()
{ {
if ($this->option('can-i-restart-this-worker')) { if ($this->option('can-i-restart-this-worker')) {
return $this->canIRestartThisWorker(); return $this->isThereAJobInProgress();
} }
if ($this->option('job-status')) {
return $this->getJobStatus($this->option('job-status'));
}
$action = select( $action = select(
label: 'What to do?', label: 'What to do?',
options: [ options: [
'pending' => 'Pending Jobs', 'pending' => 'Pending Jobs',
'running' => 'Running Jobs', 'running' => 'Running Jobs',
'can-i-restart-this-worker' => 'Can I restart this worker?', 'can-i-restart-this-worker' => 'Can I restart this worker?',
'job-status' => 'Job Status',
'workers' => 'Workers', 'workers' => 'Workers',
'failed' => 'Failed Jobs', 'failed' => 'Failed Jobs',
'failed-delete' => 'Failed Jobs - Delete', 'failed-delete' => 'Failed Jobs - Delete',
@@ -39,13 +47,13 @@ class HorizonManage extends Command
); );
if ($action === 'can-i-restart-this-worker') { if ($action === 'can-i-restart-this-worker') {
$runningJobs = ApplicationDeploymentQueue::where('horizon_job_worker', gethostname())->where('horizon_job_status', 'reserved')->get(); $this->isThereAJobInProgress();
$count = $runningJobs->count();
if ($count > 0) {
return false;
} }
return true; if ($action === 'job-status') {
$jobId = text('Which job to check?');
$jobStatus = $this->getJobStatus($jobId);
$this->info('Job Status: '.$jobStatus);
} }
if ($action === 'pending') { if ($action === 'pending') {
@@ -152,14 +160,24 @@ class HorizonManage extends Command
} }
} }
public function canIRestartThisWorker() public function isThereAJobInProgress()
{ {
$runningJobs = ApplicationDeploymentQueue::where('horizon_job_worker', gethostname())->where('horizon_job_status', 'reserved')->get(); $runningJobs = ApplicationDeploymentQueue::where('horizon_job_worker', gethostname())->where('status', ApplicationDeploymentStatus::IN_PROGRESS->value)->get();
$count = $runningJobs->count(); $count = $runningJobs->count();
if ($count > 0) { if ($count === 0) {
return false; return false;
} }
return true; return true;
} }
public function getJobStatus(string $jobId)
{
$jobFound = app(JobRepository::class)->getJobs([$jobId]);
if ($jobFound->isEmpty()) {
return 'unknown';
}
return $jobFound->first()->status;
}
} }

View File

@@ -2395,7 +2395,6 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
) { ) {
$this->application_deployment_queue->update([ $this->application_deployment_queue->update([
'status' => $status, 'status' => $status,
'horizon_job_status' => $status,
]); ]);
} }
if ($this->application_deployment_queue->status === ApplicationDeploymentStatus::FAILED->value) { if ($this->application_deployment_queue->status === ApplicationDeploymentStatus::FAILED->value) {

View File

@@ -14,6 +14,8 @@ class Show extends Component
public string $deployment_uuid; public string $deployment_uuid;
public string $horizon_job_status;
public $isKeepAliveOn = true; public $isKeepAliveOn = true;
protected $listeners = ['refreshQueue']; protected $listeners = ['refreshQueue'];
@@ -52,7 +54,9 @@ class Show extends Component
} }
$this->application = $application; $this->application = $application;
$this->application_deployment_queue = $application_deployment_queue; $this->application_deployment_queue = $application_deployment_queue;
$this->horizon_job_status = $this->application_deployment_queue->getHorizonJobStatus();
$this->deployment_uuid = $deploymentUuid; $this->deployment_uuid = $deploymentUuid;
$this->isKeepAliveOn();
} }
public function refreshQueue() public function refreshQueue()
@@ -60,13 +64,21 @@ class Show extends Component
$this->application_deployment_queue->refresh(); $this->application_deployment_queue->refresh();
} }
private function isKeepAliveOn()
{
if (data_get($this->application_deployment_queue, 'status') === 'finished' || data_get($this->application_deployment_queue, 'status') === 'failed') {
$this->isKeepAliveOn = false;
} else {
$this->isKeepAliveOn = true;
}
}
public function polling() public function polling()
{ {
$this->dispatch('deploymentFinished'); $this->dispatch('deploymentFinished');
$this->application_deployment_queue->refresh(); $this->application_deployment_queue->refresh();
if (data_get($this->application_deployment_queue, 'status') === 'finished' || data_get($this->application_deployment_queue, 'status') === 'failed') { $this->horizon_job_status = $this->application_deployment_queue->getHorizonJobStatus();
$this->isKeepAliveOn = false; $this->isKeepAliveOn();
}
} }
public function getLogLinesProperty() public function getLogLinesProperty()

View File

@@ -84,7 +84,6 @@ class DeploymentNavbar extends Component
$this->application_deployment_queue->update([ $this->application_deployment_queue->update([
'current_process_id' => null, 'current_process_id' => null,
'status' => ApplicationDeploymentStatus::CANCELLED_BY_USER->value, 'status' => ApplicationDeploymentStatus::CANCELLED_BY_USER->value,
'horizon_job_status' => ApplicationDeploymentStatus::CANCELLED_BY_USER->value,
]); ]);
next_after_cancel($server); next_after_cancel($server);
} }

View File

@@ -70,6 +70,15 @@ class ApplicationDeploymentQueue extends Model
return collect(json_decode($this->logs))->where('name', $name)->first()?->output ?? null; return collect(json_decode($this->logs))->where('name', $name)->first()?->output ?? null;
} }
public function getHorizonJobStatus()
{
if (! $this->horizon_job_id) {
return 'unknown';
}
return getJobStatus($this->horizon_job_id);
}
public function commitMessage() public function commitMessage()
{ {
if (empty($this->commit_message) || is_null($this->commit_message)) { if (empty($this->commit_message) || is_null($this->commit_message)) {

View File

@@ -26,22 +26,22 @@ class HorizonServiceProvider extends ServiceProvider
*/ */
public function boot(): void public function boot(): void
{ {
// Event::listen(function (JobReserved $event) { Event::listen(function (JobReserved $event) {
// $payload = $event->payload->decoded; $payload = $event->payload->decoded;
// $jobName = $payload['displayName']; $jobName = $payload['displayName'];
// if ($jobName === 'App\Jobs\ApplicationDeploymentJob') { if ($jobName === 'App\Jobs\ApplicationDeploymentJob') {
// $tags = $payload['tags']; $tags = $payload['tags'];
$id = $payload['id'];
// $deploymentQueueId = collect($tags)->first(function ($tag) { $deploymentQueueId = collect($tags)->first(function ($tag) {
// return str_contains($tag, 'App\Models\ApplicationDeploymentQueue'); return str_contains($tag, 'App\Models\ApplicationDeploymentQueue');
// }); });
// $deploymentQueueId = explode(':', $deploymentQueueId)[1]; $deploymentQueueId = explode(':', $deploymentQueueId)[1];
// $deploymentQueue = ApplicationDeploymentQueue::find($deploymentQueueId); $deploymentQueue = ApplicationDeploymentQueue::find($deploymentQueueId);
// $deploymentQueue->update([ $deploymentQueue->update([
// 'horizon_job_status' => 'reserved', 'horizon_job_id' => $id,
// ]); ]);
// } }
// }); });
} }
} }

View File

@@ -21,6 +21,11 @@ class CustomJobRepository extends RedisJobRepository implements CustomJobReposit
return $this->getJobsByStatus('reserved'); return $this->getJobsByStatus('reserved');
} }
public function getJobStatus(string $jobId): string
{
return $this->connection()->get('job:'.$jobId.':status');
}
/** /**
* Get all jobs with a specific status. * Get all jobs with a specific status.
*/ */

View File

@@ -41,6 +41,7 @@ use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Illuminate\Support\Stringable; use Illuminate\Support\Stringable;
use Laravel\Horizon\Contracts\JobRepository;
use Lcobucci\JWT\Encoding\ChainedFormatter; use Lcobucci\JWT\Encoding\ChainedFormatter;
use Lcobucci\JWT\Encoding\JoseEncoder; use Lcobucci\JWT\Encoding\JoseEncoder;
use Lcobucci\JWT\Signer\Hmac\Sha256; use Lcobucci\JWT\Signer\Hmac\Sha256;
@@ -4069,3 +4070,13 @@ function convertGitUrl(string $gitRepository, string $deploymentType, ?GithubApp
'port' => $providerInfo['port'], 'port' => $providerInfo['port'],
]; ];
} }
function getJobStatus(string $jobId)
{
$jobFound = app(JobRepository::class)->getJobs([$jobId]);
if ($jobFound->isEmpty()) {
return 'unknown';
}
return $jobFound->first()->status;
}

View File

@@ -12,7 +12,7 @@ return new class extends Migration
public function up(): void public function up(): void
{ {
Schema::table('application_deployment_queues', function (Blueprint $table) { Schema::table('application_deployment_queues', function (Blueprint $table) {
$table->string('horizon_job_status')->nullable(); $table->string('horizon_job_id')->nullable();
$table->string('horizon_job_worker')->nullable(); $table->string('horizon_job_worker')->nullable();
}); });
} }
@@ -23,7 +23,7 @@ return new class extends Migration
public function down(): void public function down(): void
{ {
Schema::table('application_deployment_queues', function (Blueprint $table) { Schema::table('application_deployment_queues', function (Blueprint $table) {
$table->dropColumn('horizon_job_status'); $table->dropColumn('horizon_job_id');
$table->dropColumn('horizon_job_worker'); $table->dropColumn('horizon_job_worker');
}); });
} }