fix(queue): route cloud jobs to dedicated queues

Use config-based queue selection for deployment and scheduled jobs so cloud dispatches deployments to `deployments` and scheduled jobs to `crons`, while self-hosted keeps using `high`.

Add coverage for deployment queue helper, start action routing, and scheduled job manager routing.
This commit is contained in:
Andras Bacsai committed 2026-05-22 16:11:24 +02:00
1 parent 11dbcfcfe8
commit e2199f1223
8 files changed
+109 -20

No files matched your search

+13 -9
View File
@@ -11,12 +11,16 @@ use App\Models\StandaloneMysql;
use App\Models\StandalonePostgresql;
use App\Models\StandaloneRedis;
use Lorisleiva\Actions\Concerns\AsAction;
use Lorisleiva\Actions\Decorators\JobDecorator;
class StartDatabase
{
use AsAction;
public string $jobQueue = 'high';
public function configureJob(JobDecorator $job): void
{
$job->onQueue(deployment_queue());
}
public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse $database)
{
@@ -25,28 +29,28 @@ class StartDatabase
return 'Server is not functional';
}
switch ($database->getMorphClass()) {
case \App\Models\StandalonePostgresql::class:
case StandalonePostgresql::class:
$activity = StartPostgresql::run($database);
break;
case \App\Models\StandaloneRedis::class:
case StandaloneRedis::class:
$activity = StartRedis::run($database);
break;
case \App\Models\StandaloneMongodb::class:
case StandaloneMongodb::class:
$activity = StartMongodb::run($database);
break;
case \App\Models\StandaloneMysql::class:
case StandaloneMysql::class:
$activity = StartMysql::run($database);
break;
case \App\Models\StandaloneMariadb::class:
case StandaloneMariadb::class:
$activity = StartMariadb::run($database);
break;
case \App\Models\StandaloneKeydb::class:
case StandaloneKeydb::class:
$activity = StartKeydb::run($database);
break;
case \App\Models\StandaloneDragonfly::class:
case StandaloneDragonfly::class:
$activity = StartDragonfly::run($database);
break;
case \App\Models\StandaloneClickhouse::class:
case StandaloneClickhouse::class:
$activity = StartClickhouse::run($database);
break;
}
+8 -3
View File
@@ -11,14 +11,19 @@ use App\Models\StandaloneMongodb;
use App\Models\StandaloneMysql;
use App\Models\StandalonePostgresql;
use App\Models\StandaloneRedis;
use App\Notifications\Container\ContainerRestarted;
use Lorisleiva\Actions\Concerns\AsAction;
use Lorisleiva\Actions\Decorators\JobDecorator;
use Symfony\Component\Yaml\Yaml;
class StartDatabaseProxy
{
use AsAction;
public string $jobQueue = 'high';
public function configureJob(JobDecorator $job): void
{
$job->onQueue(deployment_queue());
}
public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse|ServiceDatabase $database)
{
@@ -29,7 +34,7 @@ class StartDatabaseProxy
$proxyContainerName = "{$database->uuid}-proxy";
$isSSLEnabled = $database->enable_ssl ?? false;
if ($database->getMorphClass() === \App\Models\ServiceDatabase::class) {
if ($database->getMorphClass() === ServiceDatabase::class) {
$databaseType = $database->databaseType();
$network = $database->service->uuid;
$server = data_get($database, 'service.destination.server');
@@ -132,7 +137,7 @@ class StartDatabaseProxy
?? data_get($database, 'service.environment.project.team');
$team?->notify(
new \App\Notifications\Container\ContainerRestarted(
new ContainerRestarted(
"TCP Proxy for {$database->name} database has been disabled due to error: {$e->getMessage()}",
$server,
)
+5 -1
View File
@@ -4,13 +4,17 @@ namespace App\Actions\Service;
use App\Models\Service;
use Lorisleiva\Actions\Concerns\AsAction;
use Lorisleiva\Actions\Decorators\JobDecorator;
use Symfony\Component\Yaml\Yaml;
class StartService
{
use AsAction;
public string $jobQueue = 'high';
public function configureJob(JobDecorator $job): void
{
$job->onQueue(deployment_queue());
}
public function handle(Service $service, bool $pullLatestImages = false, bool $stopBeforeStart = false)
{
+1 -1
View File
@@ -197,7 +197,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
public function __construct(public int $application_deployment_queue_id)
{
$this->onQueue('high');
$this->onQueue(deployment_queue());
$this->application_deployment_queue = ApplicationDeploymentQueue::find($this->application_deployment_queue_id);
$this->nixpacks_plan_json = collect([]);
+7 -6
View File
@@ -40,14 +40,15 @@ class ScheduledJobManager implements ShouldQueue
$this->onQueue($this->determineQueue());
}
/**
* On cloud this job runs on a dedicated `crons` queue so it can be drained by an isolated
* Horizon worker pool; self-hosted keeps it on the shared `high` queue. Routing is decided
* by `isCloud()` (config-based), so the dispatching process needs no special env — only
* the worker must be configured to drain `crons` via `HORIZON_QUEUES`.
*/
private function determineQueue(): string
{
$preferredQueue = 'crons';
$fallbackQueue = 'high';
$configuredQueues = explode(',', env('HORIZON_QUEUES', 'high,default'));
return in_array($preferredQueue, $configuredQueues) ? $preferredQueue : $fallbackQueue;
return isCloud() ? 'crons' : 'high';
}
/**