fix: surface gateway failure details

This commit is contained in:
Peter Steinberger
2025-12-19 18:48:30 +01:00
parent 77104395ce
commit f929e1b105
2 changed files with 26 additions and 1 deletions

View File

@@ -46,6 +46,9 @@ final class GatewayProcessManager {
private(set) var restartCount: Int = 0 private(set) var restartCount: Int = 0
private(set) var environmentStatus: GatewayEnvironmentStatus = .checking private(set) var environmentStatus: GatewayEnvironmentStatus = .checking
private(set) var existingGatewayDetails: String? private(set) var existingGatewayDetails: String?
private(set) var lastFailureReason: String?
private(set) var lastExitCode: Int32?
private(set) var lastSubprocessError: String?
private var execution: Execution? private var execution: Execution?
private var lastPid: Int32? private var lastPid: Int32?
@@ -133,6 +136,9 @@ final class GatewayProcessManager {
self.desiredActive = false self.desiredActive = false
self.stopping = true self.stopping = true
self.existingGatewayDetails = nil self.existingGatewayDetails = nil
self.lastFailureReason = nil
self.lastExitCode = nil
self.lastSubprocessError = nil
guard let execution else { guard let execution else {
self.status = .stopped self.status = .stopped
return return
@@ -270,6 +276,9 @@ final class GatewayProcessManager {
private func didStart(_ execution: Execution) { private func didStart(_ execution: Execution) {
self.execution = execution self.execution = execution
self.stopping = false self.stopping = false
self.lastFailureReason = nil
self.lastExitCode = nil
self.lastSubprocessError = nil
self.status = .running(pid: execution.processIdentifier.value) self.status = .running(pid: execution.processIdentifier.value)
self.lastPid = execution.processIdentifier.value self.lastPid = execution.processIdentifier.value
self.logger.info("gateway started pid \(execution.processIdentifier.value)") self.logger.info("gateway started pid \(execution.processIdentifier.value)")
@@ -303,13 +312,15 @@ final class GatewayProcessManager {
return return
} }
self.lastExitCode = code
self.lastFailureReason = "Gateway exited (code \(code))."
self.recentCrashes.append(Date()) self.recentCrashes.append(Date())
self.recentCrashes = self.recentCrashes.filter { Date().timeIntervalSince($0) < self.crashWindow } self.recentCrashes = self.recentCrashes.filter { Date().timeIntervalSince($0) < self.crashWindow }
self.restartCount += 1 self.restartCount += 1
self.appendLog("[gateway] exited (\(code)).\n") self.appendLog("[gateway] exited (\(code)).\n")
if self.shouldGiveUpAfterCrashes() { if self.shouldGiveUpAfterCrashes() {
self.status = .failed("Too many crashes; stopped auto-restart.") self.status = .failed("Too many crashes; last exit code \(code).")
self.logger.error("gateway crash loop detected; giving up") self.logger.error("gateway crash loop detected; giving up")
return return
} }
@@ -326,7 +337,9 @@ final class GatewayProcessManager {
var message = error.localizedDescription var message = error.localizedDescription
if let sp = error as? SubprocessError { if let sp = error as? SubprocessError {
message = "SubprocessError \(sp.code.value): \(sp)" message = "SubprocessError \(sp.code.value): \(sp)"
self.lastSubprocessError = message
} }
self.lastFailureReason = message
self.appendLog("[gateway] failed: \(message)\n") self.appendLog("[gateway] failed: \(message)\n")
self.logger.error("gateway failed: \(message, privacy: .public)") self.logger.error("gateway failed: \(message, privacy: .public)")
if self.desiredActive, !self.shouldGiveUpAfterCrashes() { if self.desiredActive, !self.shouldGiveUpAfterCrashes() {

View File

@@ -333,6 +333,18 @@ struct GeneralSettings: View {
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
} }
if let failure = self.gatewayManager.lastFailureReason {
Text("Last failure: \(failure)")
.font(.caption)
.foregroundStyle(.red)
}
if let exitCode = self.gatewayManager.lastExitCode {
Text("Last exit code: \(exitCode)")
.font(.caption2)
.foregroundStyle(.secondary)
}
HStack(spacing: 10) { HStack(spacing: 10) {
Button { Button {
Task { await self.installGateway() } Task { await self.installGateway() }