CluPilotCloud/app/Services/Deployment/WatchdogLog.php

67 lines
2.1 KiB
PHP

<?php
namespace App\Services\Deployment;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\File;
use Throwable;
/**
* Was der Wächter zuletzt getan hat.
*
* Eigene Klasse und nicht ein weiteres Feld in `UpdateChannel`: der Wächter
* ist eine andere Sache als der Update-Kanal — er richtet einen liegen
* gebliebenen Stapel, während jener eine Auslieferung vermittelt. Und
* `UpdateChannel` ist bereits über neunhundert Zeilen lang.
*/
class WatchdogLog
{
private const FILE = 'deploy/watchdog-last-run.json';
/**
* Älter als das, und der Wächter läuft nicht mehr.
*
* Sein Zeitgeber steht auf einer Minute. Fünf lässt vier ausgefallenen
* Takten Luft — ein Wirt unter Last oder ein Lauf, der gerade heilt und
* dabei `sleep 15` macht, ist noch kein toter Wächter.
*/
private const STALE_AFTER_MINUTES = 5;
/**
* @return array{at: Carbon, outcome: string, actions: array<int, string>, stale: bool}|null
*/
public function lastRun(): ?array
{
try {
$path = storage_path('app/'.self::FILE);
if (! File::exists($path)) {
return null;
}
$data = json_decode((string) File::get($path), true);
if (! is_array($data) || ! isset($data['at'])) {
return null;
}
$at = Carbon::parse((string) $data['at']);
return [
'at' => $at,
'outcome' => (string) ($data['outcome'] ?? 'idle'),
'actions' => array_values(array_filter(
is_array($data['actions'] ?? null) ? $data['actions'] : [],
'is_string'
)),
'stale' => $at->lt(Carbon::now()->subMinutes(self::STALE_AFTER_MINUTES)),
];
} catch (Throwable) {
// Dieselbe Haltung wie `UpdateChannel::readJson()`: die Konsole
// liest das bei jedem Seitenaufbau, und „ich weiß es nicht" ist
// ein brauchbarer Zustand — eine geworfene Ausnahme nicht.
return null;
}
}
}