From 80b8b219a26c22e287f07673f5406dcda9423273 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Sun, 4 Oct 2026 00:11:12 +0200 Subject: [PATCH] fix(queues): run service restarts and proxy start/restart on the deployments queue - On cloud, RestartService and RestartServiceApplication now run on the deployments queue instead of high. - StartProxy and RestartProxyJob, and the remote processes they start, now run on the deployments queue. - Self-hosted still uses the high queue. - Tests cover the new routing. Co-Authored-By: Claude Opus 5.5 --- app/Actions/Proxy/StartProxy.php | 8 +++++- app/Actions/Service/RestartService.php | 6 ++++- .../Service/RestartServiceApplication.php | 6 ++++- app/Jobs/RestartProxyJob.php | 8 ++++-- bootstrap/helpers/shared.php | 3 ++- tests/Feature/QueueRoutingTest.php | 25 +++++++++++++++++++ 6 files changed, 50 insertions(+), 6 deletions(-) diff --git a/app/Actions/Proxy/StartProxy.php b/app/Actions/Proxy/StartProxy.php index 3508a46302..169064e180 100644 --- a/app/Actions/Proxy/StartProxy.php +++ b/app/Actions/Proxy/StartProxy.php @@ -8,12 +8,18 @@ use App\Events\ProxyStatusChangedUI; use App\Models\Server; use App\Services\ProxyPortParser; use Lorisleiva\Actions\Concerns\AsAction; +use Lorisleiva\Actions\Decorators\JobDecorator; use Spatie\Activitylog\Models\Activity; class StartProxy { use AsAction; + public function configureJob(JobDecorator $job): void + { + $job->onQueue(deployment_queue()); + } + public function handle(Server $server, bool $async = true, bool $force = false, bool $restarting = false): string|Activity { $proxyType = $server->proxyType(); @@ -87,7 +93,7 @@ class StartProxy } if ($async) { - return remote_process($commands, $server, callEventOnFinish: 'ProxyStatusChanged', callEventData: $server->id); + return remote_process($commands, $server, callEventOnFinish: 'ProxyStatusChanged', callEventData: $server->id, queue: deployment_queue()); } else { instant_remote_process($commands, $server); diff --git a/app/Actions/Service/RestartService.php b/app/Actions/Service/RestartService.php index 6acd3b0a43..4092fb3176 100644 --- a/app/Actions/Service/RestartService.php +++ b/app/Actions/Service/RestartService.php @@ -4,12 +4,16 @@ namespace App\Actions\Service; use App\Models\Service; use Lorisleiva\Actions\Concerns\AsAction; +use Lorisleiva\Actions\Decorators\JobDecorator; class RestartService { use AsAction; - public string $jobQueue = 'high'; + public function configureJob(JobDecorator $job): void + { + $job->onQueue(deployment_queue()); + } public function handle(Service $service, bool $pullLatestImages) { diff --git a/app/Actions/Service/RestartServiceApplication.php b/app/Actions/Service/RestartServiceApplication.php index ebee6e2f27..94c06ca653 100644 --- a/app/Actions/Service/RestartServiceApplication.php +++ b/app/Actions/Service/RestartServiceApplication.php @@ -5,12 +5,16 @@ namespace App\Actions\Service; use App\Models\ServiceApplication; use App\Models\ServiceDatabase; use Lorisleiva\Actions\Concerns\AsAction; +use Lorisleiva\Actions\Decorators\JobDecorator; class RestartServiceApplication { use AsAction; - public string $jobQueue = 'high'; + public function configureJob(JobDecorator $job): void + { + $job->onQueue(deployment_queue()); + } public function handle(ServiceApplication|ServiceDatabase $serviceApplication): void { diff --git a/app/Jobs/RestartProxyJob.php b/app/Jobs/RestartProxyJob.php index b74d8f83a7..c99cf9d9eb 100644 --- a/app/Jobs/RestartProxyJob.php +++ b/app/Jobs/RestartProxyJob.php @@ -31,7 +31,10 @@ class RestartProxyJob implements ShouldBeEncrypted, ShouldQueue return [(new WithoutOverlapping('restart-proxy-'.$this->server->uuid))->expireAfter(120)->dontRelease()]; } - public function __construct(public Server $server) {} + public function __construct(public Server $server) + { + $this->onQueue(deployment_queue()); + } public function handle() { @@ -56,7 +59,8 @@ class RestartProxyJob implements ShouldBeEncrypted, ShouldQueue $commands, $this->server, callEventOnFinish: 'ProxyStatusChanged', - callEventData: $this->server->id + callEventData: $this->server->id, + queue: deployment_queue(), ); // Store activity ID and notify UI immediately with it diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index eccba95fd1..7494787459 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -1021,7 +1021,8 @@ function isCloud(): bool } /** - * Resolve the queue used for application deployments, database starts and service starts. + * Resolve the queue used for application deployments and for database, service and proxy + * starts and restarts. * * On cloud these jobs run on a dedicated `deployments` queue so they can be drained by an * isolated Horizon worker pool; self-hosted keeps them on the shared `high` queue. Routing diff --git a/tests/Feature/QueueRoutingTest.php b/tests/Feature/QueueRoutingTest.php index 717b4a5b41..98c4f3123e 100644 --- a/tests/Feature/QueueRoutingTest.php +++ b/tests/Feature/QueueRoutingTest.php @@ -3,10 +3,15 @@ use App\Actions\Database\RestartDatabase; use App\Actions\Database\StartDatabase; use App\Actions\Database\StartDatabaseProxy; +use App\Actions\Proxy\StartProxy; +use App\Actions\Service\RestartService; +use App\Actions\Service\RestartServiceApplication; use App\Actions\Service\StartService; use App\Jobs\DatabaseBackupJob; +use App\Jobs\RestartProxyJob; use App\Jobs\ScheduledJobManager; use App\Models\ScheduledDatabaseBackup; +use App\Models\Server; describe('deployment_queue helper', function () { test('uses the high queue on self-hosted', function () { @@ -46,6 +51,9 @@ describe('start action job routing', function () { RestartDatabase::class, StartDatabaseProxy::class, StartService::class, + RestartService::class, + RestartServiceApplication::class, + StartProxy::class, ]); test('routes to the high queue on self-hosted', function (string $actionClass) { @@ -57,9 +65,26 @@ describe('start action job routing', function () { RestartDatabase::class, StartDatabaseProxy::class, StartService::class, + RestartService::class, + RestartServiceApplication::class, + StartProxy::class, ]); }); +describe('proxy restart job routing', function () { + test('routes to the deployments queue on cloud', function () { + config(['constants.coolify.self_hosted' => false]); + + expect((new RestartProxyJob(new Server))->queue)->toBe('deployments'); + }); + + test('routes to the high queue on self-hosted', function () { + config(['constants.coolify.self_hosted' => true]); + + expect((new RestartProxyJob(new Server))->queue)->toBe('high'); + }); +}); + describe('scheduled job routing', function () { test('scheduled jobs use the crons queue on cloud', function () { config(['constants.coolify.self_hosted' => false]);