macOS: fix health shell timeout race
This commit is contained in:
@@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user