diff --git a/app/Console/Commands/HorizonManage.php b/app/Console/Commands/HorizonManage.php index de4a5a264..9acc16ed6 100644 --- a/app/Console/Commands/HorizonManage.php +++ b/app/Console/Commands/HorizonManage.php @@ -2,6 +2,7 @@ namespace App\Console\Commands; +use App\Enums\ApplicationDeploymentStatus; use App\Models\ApplicationDeploymentQueue; use App\Repositories\CustomJobRepository; use Illuminate\Console\Command; @@ -13,24 +14,31 @@ use Laravel\Horizon\Repositories\RedisJobRepository; use function Laravel\Prompts\multiselect; use function Laravel\Prompts\select; use function Laravel\Prompts\table; +use function Laravel\Prompts\text; 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'; public function handle() { 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( label: 'What to do?', options: [ 'pending' => 'Pending Jobs', 'running' => 'Running Jobs', 'can-i-restart-this-worker' => 'Can I restart this worker?', + 'job-status' => 'Job Status', 'workers' => 'Workers', 'failed' => 'Failed Jobs', 'failed-delete' => 'Failed Jobs - Delete', @@ -39,13 +47,13 @@ class HorizonManage extends Command ); if ($action === 'can-i-restart-this-worker') { - $runningJobs = ApplicationDeploymentQueue::where('horizon_job_worker', gethostname())->where('horizon_job_status', 'reserved')->get(); - $count = $runningJobs->count(); - if ($count > 0) { - return false; - } + $this->isThereAJobInProgress(); + } - return true; + if ($action === 'job-status') { + $jobId = text('Which job to check?'); + $jobStatus = $this->getJobStatus($jobId); + $this->info('Job Status: '.$jobStatus); } 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(); - if ($count > 0) { + if ($count === 0) { return false; } return true; } + + public function getJobStatus(string $jobId) + { + $jobFound = app(JobRepository::class)->getJobs([$jobId]); + if ($jobFound->isEmpty()) { + return 'unknown'; + } + + return $jobFound->first()->status; + } } diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 1b92f817b..309201653 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -2395,7 +2395,6 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); ) { $this->application_deployment_queue->update([ 'status' => $status, - 'horizon_job_status' => $status, ]); } if ($this->application_deployment_queue->status === ApplicationDeploymentStatus::FAILED->value) { diff --git a/app/Livewire/Project/Application/Deployment/Show.php b/app/Livewire/Project/Application/Deployment/Show.php index 04170fa28..fadc0ed5e 100644 --- a/app/Livewire/Project/Application/Deployment/Show.php +++ b/app/Livewire/Project/Application/Deployment/Show.php @@ -14,6 +14,8 @@ class Show extends Component public string $deployment_uuid; + public string $horizon_job_status; + public $isKeepAliveOn = true; protected $listeners = ['refreshQueue']; @@ -52,7 +54,9 @@ class Show extends Component } $this->application = $application; $this->application_deployment_queue = $application_deployment_queue; + $this->horizon_job_status = $this->application_deployment_queue->getHorizonJobStatus(); $this->deployment_uuid = $deploymentUuid; + $this->isKeepAliveOn(); } public function refreshQueue() @@ -60,13 +64,21 @@ class Show extends Component $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() { $this->dispatch('deploymentFinished'); $this->application_deployment_queue->refresh(); - if (data_get($this->application_deployment_queue, 'status') === 'finished' || data_get($this->application_deployment_queue, 'status') === 'failed') { - $this->isKeepAliveOn = false; - } + $this->horizon_job_status = $this->application_deployment_queue->getHorizonJobStatus(); + $this->isKeepAliveOn(); } public function getLogLinesProperty() diff --git a/app/Livewire/Project/Application/DeploymentNavbar.php b/app/Livewire/Project/Application/DeploymentNavbar.php index 8210a12a1..6a6fa2482 100644 --- a/app/Livewire/Project/Application/DeploymentNavbar.php +++ b/app/Livewire/Project/Application/DeploymentNavbar.php @@ -84,7 +84,6 @@ class DeploymentNavbar extends Component $this->application_deployment_queue->update([ 'current_process_id' => null, 'status' => ApplicationDeploymentStatus::CANCELLED_BY_USER->value, - 'horizon_job_status' => ApplicationDeploymentStatus::CANCELLED_BY_USER->value, ]); next_after_cancel($server); } diff --git a/app/Models/ApplicationDeploymentQueue.php b/app/Models/ApplicationDeploymentQueue.php index c261c30c6..f6a88a692 100644 --- a/app/Models/ApplicationDeploymentQueue.php +++ b/app/Models/ApplicationDeploymentQueue.php @@ -70,6 +70,15 @@ class ApplicationDeploymentQueue extends Model 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() { if (empty($this->commit_message) || is_null($this->commit_message)) { diff --git a/app/Providers/HorizonServiceProvider.php b/app/Providers/HorizonServiceProvider.php index e89528d4c..efe17cd7e 100644 --- a/app/Providers/HorizonServiceProvider.php +++ b/app/Providers/HorizonServiceProvider.php @@ -26,22 +26,22 @@ class HorizonServiceProvider extends ServiceProvider */ public function boot(): void { - // Event::listen(function (JobReserved $event) { - // $payload = $event->payload->decoded; - // $jobName = $payload['displayName']; - // if ($jobName === 'App\Jobs\ApplicationDeploymentJob') { - // $tags = $payload['tags']; - - // $deploymentQueueId = collect($tags)->first(function ($tag) { - // return str_contains($tag, 'App\Models\ApplicationDeploymentQueue'); - // }); - // $deploymentQueueId = explode(':', $deploymentQueueId)[1]; - // $deploymentQueue = ApplicationDeploymentQueue::find($deploymentQueueId); - // $deploymentQueue->update([ - // 'horizon_job_status' => 'reserved', - // ]); - // } - // }); + Event::listen(function (JobReserved $event) { + $payload = $event->payload->decoded; + $jobName = $payload['displayName']; + if ($jobName === 'App\Jobs\ApplicationDeploymentJob') { + $tags = $payload['tags']; + $id = $payload['id']; + $deploymentQueueId = collect($tags)->first(function ($tag) { + return str_contains($tag, 'App\Models\ApplicationDeploymentQueue'); + }); + $deploymentQueueId = explode(':', $deploymentQueueId)[1]; + $deploymentQueue = ApplicationDeploymentQueue::find($deploymentQueueId); + $deploymentQueue->update([ + 'horizon_job_id' => $id, + ]); + } + }); } } diff --git a/app/Repositories/CustomJobRepository.php b/app/Repositories/CustomJobRepository.php index 518be844f..af299895d 100644 --- a/app/Repositories/CustomJobRepository.php +++ b/app/Repositories/CustomJobRepository.php @@ -21,6 +21,11 @@ class CustomJobRepository extends RedisJobRepository implements CustomJobReposit return $this->getJobsByStatus('reserved'); } + public function getJobStatus(string $jobId): string + { + return $this->connection()->get('job:'.$jobId.':status'); + } + /** * Get all jobs with a specific status. */ diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 7aa411cd1..74220a1f9 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -41,6 +41,7 @@ use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; use Illuminate\Support\Stringable; +use Laravel\Horizon\Contracts\JobRepository; use Lcobucci\JWT\Encoding\ChainedFormatter; use Lcobucci\JWT\Encoding\JoseEncoder; use Lcobucci\JWT\Signer\Hmac\Sha256; @@ -4069,3 +4070,13 @@ function convertGitUrl(string $gitRepository, string $deploymentType, ?GithubApp 'port' => $providerInfo['port'], ]; } + +function getJobStatus(string $jobId) +{ + $jobFound = app(JobRepository::class)->getJobs([$jobId]); + if ($jobFound->isEmpty()) { + return 'unknown'; + } + + return $jobFound->first()->status; +} diff --git a/database/migrations/2025_01_10_135244_add_horizon_job_details_to_queue.php b/database/migrations/2025_01_10_135244_add_horizon_job_details_to_queue.php index e6d4693a7..8ce5821ef 100644 --- a/database/migrations/2025_01_10_135244_add_horizon_job_details_to_queue.php +++ b/database/migrations/2025_01_10_135244_add_horizon_job_details_to_queue.php @@ -12,7 +12,7 @@ return new class extends Migration public function up(): void { 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(); }); } @@ -23,7 +23,7 @@ return new class extends Migration public function down(): void { Schema::table('application_deployment_queues', function (Blueprint $table) { - $table->dropColumn('horizon_job_status'); + $table->dropColumn('horizon_job_id'); $table->dropColumn('horizon_job_worker'); }); }