Files
keystone/app/Actions/Environments/PlanEnvironmentDeployment.php

92 lines
3.0 KiB
PHP

<?php
namespace App\Actions\Environments;
use App\Data\Environments\EnvironmentDeploymentPlan;
use App\Enums\DeployPolicy;
use App\Enums\EnvironmentAttachmentRole;
use App\Enums\SchedulerMode;
use App\Models\Environment;
class PlanEnvironmentDeployment
{
public function execute(Environment $environment): EnvironmentDeploymentPlan
{
$environment->loadMissing([
'services',
'attachments.service',
'attachments.serviceSlice',
]);
$deployableServices = $environment->services
->where('deploy_policy', DeployPolicy::WITH_ENVIRONMENT)
->values();
$dependencies = $environment->attachments
->map(fn ($attachment) => $attachment->service)
->filter()
->unique('id')
->values();
$targetServerCount = $deployableServices
->flatMap(fn ($service) => $service->replicas->pluck('server_id')->filter())
->unique()
->count();
if ($targetServerCount === 0) {
$targetServerCount = $deployableServices->sum('desired_replicas') > 1 ? 2 : 1;
}
return new EnvironmentDeploymentPlan(
services: $deployableServices->all(),
dependencies: $dependencies->all(),
requiresRegistry: $targetServerCount > 1 && $environment->application->organisation->registries()->doesntExist(),
warnings: $this->warnings($environment),
blockers: $this->blockers($environment),
);
}
/**
* @return array<int, string>
*/
private function warnings(Environment $environment): array
{
$warnings = [];
if ($environment->variables()
->where('key', 'QUEUE_CONNECTION')
->get()
->contains(fn ($variable) => $variable->value === 'sync')) {
$warnings[] = 'QUEUE_CONNECTION=sync is not recommended for deployed Laravel environments.';
}
if ($environment->attachments->contains('role', EnvironmentAttachmentRole::QUEUE)) {
$hasWorker = $environment->services->contains(fn ($service) => in_array('worker', $service->process_roles ?? [], true));
if (! $hasWorker) {
$warnings[] = 'Queue attachment exists without a dedicated worker service.';
}
}
return $warnings;
}
/**
* @return array<int, string>
*/
private function blockers(Environment $environment): array
{
if (! $environment->scheduler_enabled || $environment->scheduler_mode !== SchedulerMode::SINGLE) {
return [];
}
$target = $environment->services->firstWhere('id', $environment->scheduler_target_service_id);
if ($target && $target->desired_replicas > 1 && in_array('scheduler', $target->process_roles ?? [], true)) {
return ['Scheduler mode single requires the scheduler target service to run exactly one replica.'];
}
return [];
}
}