onQueue('v5-reconcile'); } public function handle(): void { $this->dispatchReconcileJobs(); $this->pruneContainerStatuses(); } private function dispatchReconcileJobs(): void { V5Server::query() // Unreachable servers stay in the loop so a recovered node is // restored to installed by its next successful reconcile. ->whereIn('status', [ServerStatus::Installed->value, ServerStatus::Unreachable->value]) ->where('has_coold', true) ->get() ->each(function (V5Server $server): void { try { V5ReconcileServerStateJob::dispatch($server->id); } catch (\Throwable $exception) { Log::warning('V5 reconcile dispatch failed for a server.', [ 'server_id' => $server->id, 'error' => $exception->getMessage(), ]); } }); } private function pruneContainerStatuses(): void { $cutoff = now()->subHours(self::CONTAINER_STATUS_TTL_HOURS); $liveContainerIds = V5Application::query() ->whereNotNull('runtime_container_id') ->pluck('runtime_container_id') ->all(); ContainerStatus::query() ->where(function ($query) use ($cutoff): void { $query ->where('last_seen_at', '<', $cutoff) ->orWhere(function ($query) use ($cutoff): void { $query->whereNull('last_seen_at')->where('created_at', '<', $cutoff); }) ->orWhereNotIn('server_id', V5Server::query()->select('id')); }) ->when($liveContainerIds !== [], fn ($query) => $query->whereNotIn('container_id', $liveContainerIds)) ->delete(); } }