fix(macos): drain subprocess pipes before wait (#1081)
Thanks @thesash. Co-authored-by: Sash Catanzarite <sashcatanzarite@Sash-MacBook-Pro-14in-3.local>
This commit is contained in:
@@ -44,6 +44,7 @@
|
|||||||
- Plugins: add zip installs and `--link` to avoid copying local paths.
|
- Plugins: add zip installs and `--link` to avoid copying local paths.
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
- macOS: drain subprocess pipes before waiting to avoid deadlocks. (#1081) — thanks @thesash.
|
||||||
- Telegram: accept tg/group/telegram prefixes + topic targets for inline button validation. (#1072) — thanks @danielz1z.
|
- Telegram: accept tg/group/telegram prefixes + topic targets for inline button validation. (#1072) — thanks @danielz1z.
|
||||||
- Sub-agents: normalize announce delivery origin + queue bucketing by accountId to keep multi-account routing stable. (#1061, #1058) — thanks @adam91holt.
|
- Sub-agents: normalize announce delivery origin + queue bucketing by accountId to keep multi-account routing stable. (#1061, #1058) — thanks @adam91holt.
|
||||||
- Sessions: include deliveryContext in sessions.list and reuse normalized delivery routing for announce/restart fallbacks. (#1058)
|
- Sessions: include deliveryContext in sessions.list and reuse normalized delivery routing for announce/restart fallbacks. (#1058)
|
||||||
|
|||||||
@@ -279,6 +279,8 @@ enum GatewayEnvironment {
|
|||||||
process.standardError = pipe
|
process.standardError = pipe
|
||||||
do {
|
do {
|
||||||
try process.run()
|
try process.run()
|
||||||
|
// Read pipe before waitUntilExit to avoid potential deadlock
|
||||||
|
let data = pipe.fileHandleForReading.readToEndSafely()
|
||||||
process.waitUntilExit()
|
process.waitUntilExit()
|
||||||
let elapsedMs = Int(Date().timeIntervalSince(start) * 1000)
|
let elapsedMs = Int(Date().timeIntervalSince(start) * 1000)
|
||||||
if elapsedMs > 500 {
|
if elapsedMs > 500 {
|
||||||
@@ -294,7 +296,6 @@ enum GatewayEnvironment {
|
|||||||
bin=\(binary, privacy: .public)
|
bin=\(binary, privacy: .public)
|
||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
let data = pipe.fileHandleForReading.readToEndSafely()
|
|
||||||
let raw = String(data: data, encoding: .utf8)?
|
let raw = String(data: data, encoding: .utf8)?
|
||||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
return Semver.parse(raw)
|
return Semver.parse(raw)
|
||||||
|
|||||||
@@ -17,8 +17,11 @@ enum Launchctl {
|
|||||||
process.standardError = pipe
|
process.standardError = pipe
|
||||||
do {
|
do {
|
||||||
try process.run()
|
try process.run()
|
||||||
process.waitUntilExit()
|
// Read pipe output BEFORE waitUntilExit to avoid deadlock.
|
||||||
|
// If the process writes enough to fill the pipe buffer (~64KB),
|
||||||
|
// it will block until someone reads. Reading first prevents this.
|
||||||
let data = pipe.fileHandleForReading.readToEndSafely()
|
let data = pipe.fileHandleForReading.readToEndSafely()
|
||||||
|
process.waitUntilExit()
|
||||||
let output = String(data: data, encoding: .utf8) ?? ""
|
let output = String(data: data, encoding: .utf8) ?? ""
|
||||||
return Result(status: process.terminationStatus, output: output)
|
return Result(status: process.terminationStatus, output: output)
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -204,14 +204,15 @@ actor PortGuardian {
|
|||||||
proc.standardError = Pipe()
|
proc.standardError = Pipe()
|
||||||
do {
|
do {
|
||||||
try proc.run()
|
try proc.run()
|
||||||
|
// Read pipe before waitUntilExit to avoid potential deadlock
|
||||||
|
let data = pipe.fileHandleForReading.readToEndSafely()
|
||||||
proc.waitUntilExit()
|
proc.waitUntilExit()
|
||||||
|
guard !data.isEmpty else { return nil }
|
||||||
|
return String(data: data, encoding: .utf8)?
|
||||||
|
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
} catch {
|
} catch {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
let data = pipe.fileHandleForReading.readToEndSafely()
|
|
||||||
guard !data.isEmpty else { return nil }
|
|
||||||
return String(data: data, encoding: .utf8)?
|
|
||||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func parseListeners(from text: String) -> [Listener] {
|
private static func parseListeners(from text: String) -> [Listener] {
|
||||||
|
|||||||
@@ -134,6 +134,8 @@ enum RuntimeLocator {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
try process.run()
|
try process.run()
|
||||||
|
// Read pipe before waitUntilExit to avoid potential deadlock
|
||||||
|
let data = pipe.fileHandleForReading.readToEndSafely()
|
||||||
process.waitUntilExit()
|
process.waitUntilExit()
|
||||||
let elapsedMs = Int(Date().timeIntervalSince(start) * 1000)
|
let elapsedMs = Int(Date().timeIntervalSince(start) * 1000)
|
||||||
if elapsedMs > 500 {
|
if elapsedMs > 500 {
|
||||||
@@ -149,7 +151,6 @@ enum RuntimeLocator {
|
|||||||
bin=\(binary, privacy: .public)
|
bin=\(binary, privacy: .public)
|
||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
let data = pipe.fileHandleForReading.readToEndSafely()
|
|
||||||
return String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines)
|
return String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
} catch {
|
} catch {
|
||||||
let elapsedMs = Int(Date().timeIntervalSince(start) * 1000)
|
let elapsedMs = Int(Date().timeIntervalSince(start) * 1000)
|
||||||
|
|||||||
Reference in New Issue
Block a user