From 7d35f3abac11ca33121c92c4d4446033bc91157d Mon Sep 17 00:00:00 2001 From: boban Date: Fri, 19 Jun 2026 20:10:28 +0200 Subject: [PATCH] fix(system): surface a failed restart sentinel write instead of a stuck state Mirror the update button (0.9.15): requestRestart() now returns bool and restartNow() shows an error toast (pointing at sudo ./update.sh) when the sentinel can't be written, instead of a 'restarting' state that never resolves. Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 9 +++++++++ app/Livewire/System/Index.php | 7 ++++++- app/Services/DeploymentService.php | 6 ++++-- config/clusev.php | 2 +- lang/de/system.php | 1 + lang/en/system.php | 1 + 6 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa5fae5..9783b07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,15 @@ getaggte Releases (Kanal `stable`, optional `beta`) — niemals Entwicklungs-Bui _Keine offenen Änderungen — der nächste Stand wird hier gesammelt und als `vX.Y.Z` getaggt._ +## [0.9.16] - 2026-06-19 + +### Behoben +- **Neustart-Knopf meldet einen fehlgeschlagenen Sentinel-Schreibvorgang** — konsistent mit dem + Update-Knopf (0.9.15). Konnte die Sentinel-Datei nicht geschrieben werden (z. B. bei einem + uid-Mismatch vor dem Fix), zeigte „Jetzt neu starten" nur „Neustart wird ausgeführt …" ohne dass + etwas passierte; jetzt erscheint stattdessen ein Fehler-Toast mit dem Hinweis auf `sudo ./update.sh`. + `DeploymentService::requestRestart()` gibt nun `bool` zurück. + ## [0.9.15] - 2026-06-19 ### Behoben diff --git a/app/Livewire/System/Index.php b/app/Livewire/System/Index.php index 35b8bd2..248b0b2 100644 --- a/app/Livewire/System/Index.php +++ b/app/Livewire/System/Index.php @@ -145,7 +145,12 @@ class Index extends Component */ public function restartNow(DeploymentService $deployment): void { - $deployment->requestRestart(); + // Surface a failed sentinel write instead of a "restarting" state that never resolves. + if (! $deployment->requestRestart()) { + $this->dispatch('notify', message: __('system.restart_write_failed'), level: 'error'); + + return; + } $this->restartRequested = true; $this->dispatch('notify', message: __('system.restart_running')); } diff --git a/app/Services/DeploymentService.php b/app/Services/DeploymentService.php index 35f099c..d1c89d9 100644 --- a/app/Services/DeploymentService.php +++ b/app/Services/DeploymentService.php @@ -173,7 +173,7 @@ class DeploymentService * `docker compose restart`, then removes it. The content is a non-sensitive marker * (an ISO timestamp) — the trigger is the file existing, not what it holds. Never throws. */ - public function requestRestart(): void + public function requestRestart(): bool { $path = $this->restartSignalPath(); $dir = dirname($path); @@ -182,7 +182,9 @@ class DeploymentService @mkdir($dir, 0775, true); } - @file_put_contents($path, now()->toIso8601String().PHP_EOL); + // Returns false when the (bind-mounted) sentinel dir is not writable by the app user, so + // the caller can surface that instead of a "restarting" state that never resolves. + return @file_put_contents($path, now()->toIso8601String().PHP_EOL) !== false; } /** True while a restart request is pending (the host watcher clears it once handled). */ diff --git a/config/clusev.php b/config/clusev.php index a85a1f2..5a15c13 100644 --- a/config/clusev.php +++ b/config/clusev.php @@ -2,7 +2,7 @@ return [ // First tagged release is v0.1.0 (semantic, not -dev). - 'version' => '0.9.15', + 'version' => '0.9.16', // Deployed commit + branch. install.sh bakes these into .env from the host's .git (the prod // image ships no .git); the Versions page prefers them and falls back to a live .git read in diff --git a/lang/de/system.php b/lang/de/system.php index 1073bd6..09c1509 100644 --- a/lang/de/system.php +++ b/lang/de/system.php @@ -43,6 +43,7 @@ return [ 'restart_body' => 'Die Änderung ist gespeichert. Starte den Stack neu, damit sie übernommen wird.', 'restart_now' => 'Jetzt neu starten', 'restart_running' => 'Neustart wird ausgeführt …', + 'restart_write_failed' => 'Neustart konnte nicht angestoßen werden (Sentinel nicht schreibbar). Bitte einmalig per SSH „sudo ./update.sh" aktualisieren.', 'restart_watcher_hint' => 'Falls nach ~30 s nichts passiert, ist der Host-Watcher evtl. nicht installiert — siehe Doku (docker/restart-sentinel).', 'restart_lockout_hint' => 'Nach dem Neustart eventuell neu anmelden. Falls die neue Domain (DNS/Zertifikat) noch nicht erreichbar ist, bleibt das Panel über http:// als Rückfallweg erreichbar.', diff --git a/lang/en/system.php b/lang/en/system.php index 80a7ff4..fa7af2c 100644 --- a/lang/en/system.php +++ b/lang/en/system.php @@ -43,6 +43,7 @@ return [ 'restart_body' => 'The change is saved. Restart the stack to apply it.', 'restart_now' => 'Restart now', 'restart_running' => 'Restart is running …', + 'restart_write_failed' => 'Could not start the restart (sentinel not writable). Please update once via SSH with "sudo ./update.sh".', 'restart_watcher_hint' => 'If nothing happens after ~30 s, the host watcher may not be installed — see the docs (docker/restart-sentinel).', 'restart_lockout_hint' => 'You may need to sign in again after the restart. If the new domain (DNS/certificate) is not reachable yet, the panel stays available at http:// as a fallback.',