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 */ 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 */ 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 []; } }