macOS: fix health shell timeout race

This commit is contained in:
Peter Steinberger
2025-12-07 16:48:17 +00:00
parent 71072f084e
commit 1f0ee9837b

View File

@@ -22,24 +22,32 @@ enum ShellRunner {
return Response(ok: false, message: "failed to start: \(error.localizedDescription)") return Response(ok: false, message: "failed to start: \(error.localizedDescription)")
} }
let waitTask = Task.detached { () -> (Int32, Data, Data) in let waitTask = Task { () -> Response in
process.waitUntilExit() process.waitUntilExit()
let out = stdoutPipe.fileHandleForReading.readDataToEndOfFile() let out = stdoutPipe.fileHandleForReading.readDataToEndOfFile()
let err = stderrPipe.fileHandleForReading.readDataToEndOfFile() let err = stderrPipe.fileHandleForReading.readDataToEndOfFile()
return (process.terminationStatus, out, err) let status = process.terminationStatus
let combined = out.isEmpty ? err : out
return Response(ok: status == 0, message: status == 0 ? nil : "exit \(status)", payload: combined)
} }
if let timeout, timeout > 0 { if let timeout, timeout > 0 {
let nanos = UInt64(timeout * 1_000_000_000) let nanos = UInt64(timeout * 1_000_000_000)
try? await Task.sleep(nanoseconds: nanos) let response = await withTaskGroup(of: Response.self) { group in
if process.isRunning { group.addTask { await waitTask.value }
process.terminate() group.addTask {
return Response(ok: false, message: "timeout") try? await Task.sleep(nanoseconds: nanos)
if process.isRunning { process.terminate() }
_ = await waitTask.value // drain pipes after termination
return Response(ok: false, message: "timeout")
}
let first = await group.next()!
group.cancelAll()
return first
} }
return response
} }
let (status, out, err) = await waitTask.value return await waitTask.value
let combined = out.isEmpty ? err : out
return Response(ok: status == 0, message: status == 0 ? nil : "exit \(status)", payload: combined)
} }
} }