authorize('hosts.manage'); // Through the same query that FINDS them, so "look again" can never // mean a different set of runs than the table above it is showing. app(HostCapacity::class)->parkedRuns()->update(['next_attempt_at' => now()]); $this->dispatch('notify', message: __('capacity.rechecked')); } /** * Decide which parked order goes on which host. * * The queue is read by somebody who knows things the placement rule does * not — that this customer belongs beside that one, that a machine is about * to be taken out of service, that the big order should have the new box * and the small ones can share. The rule stays in charge when nobody says * otherwise; an empty choice hands it back. * * Only the preference is written. The reservation still happens in the * provisioning step, under the placement lock, and still checks the host * has room — a console that created the instance itself would be a second * placement path with no lock and its own arithmetic. */ public function pin(int $runId, string $hostId): void { $this->authorize('hosts.manage'); // Only a run that is actually parked. Writing a host preference onto a // run that has moved on would sit in its context for ever and take // effect on a re-run months later, on a host chosen for a queue that no // longer exists. $run = app(HostCapacity::class)->parkedRuns()->whereKey($runId)->first(); if ($run === null) { return; } if ($hostId === '') { $run->forgetContext('preferred_host_id'); $this->dispatch('notify', message: __('capacity.pin_cleared')); return; } $host = Host::query()->where('status', 'active')->find((int) $hostId); if ($host === null) { return; } $run->mergeContext(['preferred_host_id' => $host->id]); // Taken up now rather than at the next tick: an operator who has just // said where it goes is watching for it to go there. $run->forceFill(['next_attempt_at' => now()])->save(); $this->dispatch('notify', message: __('capacity.pinned', ['host' => $host->name])); } public function render() { $this->authorize('hosts.manage'); $capacity = app(HostCapacity::class); $demand = $capacity->queueDemand(); return view('livewire.admin.capacity', [ 'parked' => $capacity->parked(), 'demand' => $demand, 'unplaceable' => $capacity->unplaceablePlans(), 'hosts' => Host::query()->where('status', 'active')->orderBy('name')->get(), // Only when something is actually waiting. A shopping list on an // idle estate is an invitation to spend money for no reason. 'offers' => $demand['count'] > 0 ? app(ServerMarket::class)->offers($demand['largest']) : [], ]); } }