Vapor 4部署Ubuntu后Process执行Shell命令延迟至进程退出才运行
核心根因
Linux平台Foundation库Process实现和macOS存在差异,现有执行函数缺少子进程等待逻辑、未完全消费子进程输出缓冲区,导致子进程启动后进入挂起状态,直到Vapor主进程退出时,所有挂起的子进程才会被系统回收执行,因此出现停止应用时消息批量发出的现象。
修复方案
1. 调整Shell执行函数
添加waitUntilExit调用,同时捕获标准错误输出避免缓冲区堵塞导致进程挂起:
func runShellScript(_ cmd: String) -> String? { let outputPipe = Pipe() let errorPipe = Pipe() let process = Process() process.launchPath = "/bin/sh" process.arguments = ["-c", cmd] process.standardOutput = outputPipe process.standardError = errorPipe process.launch() // 等待子进程执行完成 process.waitUntilExit() // 读取所有输出避免缓冲区残留 let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile() let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile() // 按需打印错误日志排查问题 if let errorStr = String(data: errorData, encoding: .utf8), !errorStr.isEmpty { print("Shell执行错误: \(errorStr)") } return String(data: outputData, encoding: .utf8) }
2. 适配Vapor异步特性
不要在路由的事件循环线程直接执行同步Shell调用,会堵塞事件循环影响其他请求处理,建议将调用丢到全局后台队列执行,同时对传入的消息做单引号转义避免命令注入风险:
// 路由内调用逻辑 let slackCLIPath = "/home/linuxbrew/.linuxbrew/bin/" let escapedMessage = myMessageComingFromThePOST.replacingOccurrences(of: "'", with: "'\\''") DispatchQueue.global().async { _ = runShellScript("\(slackCLIPath)slack chat send '\(escapedMessage)' '#myChannel'") }
可选优化
可以直接使用Vapor内置的ConsoleKit库的非阻塞进程执行API,原生适配Linux环境,不会堵塞事件循环,无需手动维护Process逻辑。
内容的提问来源于stack exchange,提问作者cdf1982
相关产品推荐
相关产品推荐

