Shell 通过 NSTask 进程的命令延迟到我的 Vapor 应用程序退出
Shell command via NSTask's Process delayed until my Vapor app quits
我构建了一个 Vapor 4 应用程序,目前部署在本地 Ubuntu 18 服务器虚拟机上,运行在 NGINX 后面并为用户提供服务没有任何问题。
现在 我希望我的网络服务器路由之一通过 Process
执行 Bash 命令来对特定的 POST 做出反应(这个,为了通过 slack-cli 将消息发送到专用的 Slack 频道,我已经将这个工具用于其他目的,并且已经在我的开发机器和 Ubuntu 服务器上进行了配置和工作) .
使用以下代码,当我 运行 我的 Vapor 应用程序 在我的本地机器上 (即: 在 POST 之后,预期消息立即出现在 Slack 频道中):
// What follows is placed inside my dedicated app.post route, after checking the response is valid...
let slackCLIPath = "/home/linuxbrew/.linuxbrew/bin/" // This is the slack-cli path on the Linux VM; I swap it with "/opt/homebrew/bin/" when running the app on my local Mac
_ = runShellScript("\(slackCLIPath)slack chat send '\(myMessageComingFromThePOST)' '#myChannel'")
// ...
// runShellScript() called above is the dedicated function (coming from [this SO answer]( that executes the Shell process, and its code follows:
func runShellScript(_ cmd: String) -> String? {
let pipe = Pipe()
let process = Process()
process.launchPath = "/bin/sh"
process.arguments = ["-c", String(format:"%@", cmd)]
process.standardOutput = pipe
let fileHandle = pipe.fileHandleForReading
process.launch()
return String(data: fileHandle.readDataToEndOfFile(), encoding: .utf8)
}
我的问题是,当我在 Ubuntu 服务器上部署我的应用程序时,无论是在调试还是在生产环境中,Shell 进程的执行都不像它那样发生在我的 Mac 上做了:当我 POST 到那条路线时,Vapor 没有记录任何错误,但是 Slack 中没有消息出现,即使我等了一会儿!
但这是棘手的部分:一旦我在服务器上停止我的 Vapor 应用程序,所有消息都会立即发送到 Slack.
经过大量测试(这显然包括通过使用传递给 NSTask
的 Process
class 在我的 Vapor 应用程序中),似乎 Bash 命令未执行 直到我的 Vapor 应用程序退出 .
很明显,我遗漏了一些关于如何使 Process
使用 Vapor“实时”工作的信息,我将不胜感激我能得到的所有帮助。
您需要等到任务完成。看起来你正在陷入僵局。这就是我 运行 在 Linux 上的内容:
// MARK: - Functions
@discardableResult
func shell(_ args: String..., returnStdOut: Bool = false, stdIn: Pipe? = nil) throws -> (Int32, Pipe) {
return try shell(args, returnStdOut: returnStdOut, stdIn: stdIn)
}
@discardableResult
func shell(_ args: [String], returnStdOut: Bool = false, stdIn: Pipe? = nil) throws -> (Int32, Pipe) {
let task = Process()
task.executableURL = URL(fileURLWithPath: "/usr/bin/env")
task.arguments = args
let pipe = Pipe()
if returnStdOut {
task.standardOutput = pipe
}
if let stdIn = stdIn {
task.standardInput = stdIn
}
try task.run()
task.waitUntilExit()
return (task.terminationStatus, pipe)
}
extension Pipe {
func string() -> String? {
let data = self.fileHandleForReading.readDataToEndOfFile()
let result: String?
if let string = String(data: data, encoding: String.Encoding.utf8) {
result = string
} else {
result = nil
}
return result
}
}
重要的行以 try task.run()
开始并等待 task.waitUntilExit()
我构建了一个 Vapor 4 应用程序,目前部署在本地 Ubuntu 18 服务器虚拟机上,运行在 NGINX 后面并为用户提供服务没有任何问题。
现在 我希望我的网络服务器路由之一通过 Process
执行 Bash 命令来对特定的 POST 做出反应(这个,为了通过 slack-cli 将消息发送到专用的 Slack 频道,我已经将这个工具用于其他目的,并且已经在我的开发机器和 Ubuntu 服务器上进行了配置和工作) .
使用以下代码,当我 运行 我的 Vapor 应用程序 在我的本地机器上 (即: 在 POST 之后,预期消息立即出现在 Slack 频道中):
// What follows is placed inside my dedicated app.post route, after checking the response is valid...
let slackCLIPath = "/home/linuxbrew/.linuxbrew/bin/" // This is the slack-cli path on the Linux VM; I swap it with "/opt/homebrew/bin/" when running the app on my local Mac
_ = runShellScript("\(slackCLIPath)slack chat send '\(myMessageComingFromThePOST)' '#myChannel'")
// ...
// runShellScript() called above is the dedicated function (coming from [this SO answer]( that executes the Shell process, and its code follows:
func runShellScript(_ cmd: String) -> String? {
let pipe = Pipe()
let process = Process()
process.launchPath = "/bin/sh"
process.arguments = ["-c", String(format:"%@", cmd)]
process.standardOutput = pipe
let fileHandle = pipe.fileHandleForReading
process.launch()
return String(data: fileHandle.readDataToEndOfFile(), encoding: .utf8)
}
我的问题是,当我在 Ubuntu 服务器上部署我的应用程序时,无论是在调试还是在生产环境中,Shell 进程的执行都不像它那样发生在我的 Mac 上做了:当我 POST 到那条路线时,Vapor 没有记录任何错误,但是 Slack 中没有消息出现,即使我等了一会儿!
但这是棘手的部分:一旦我在服务器上停止我的 Vapor 应用程序,所有消息都会立即发送到 Slack.
经过大量测试(这显然包括通过使用传递给 NSTask
的 Process
class 在我的 Vapor 应用程序中),似乎 Bash 命令未执行 直到我的 Vapor 应用程序退出 .
很明显,我遗漏了一些关于如何使 Process
使用 Vapor“实时”工作的信息,我将不胜感激我能得到的所有帮助。
您需要等到任务完成。看起来你正在陷入僵局。这就是我 运行 在 Linux 上的内容:
// MARK: - Functions
@discardableResult
func shell(_ args: String..., returnStdOut: Bool = false, stdIn: Pipe? = nil) throws -> (Int32, Pipe) {
return try shell(args, returnStdOut: returnStdOut, stdIn: stdIn)
}
@discardableResult
func shell(_ args: [String], returnStdOut: Bool = false, stdIn: Pipe? = nil) throws -> (Int32, Pipe) {
let task = Process()
task.executableURL = URL(fileURLWithPath: "/usr/bin/env")
task.arguments = args
let pipe = Pipe()
if returnStdOut {
task.standardOutput = pipe
}
if let stdIn = stdIn {
task.standardInput = stdIn
}
try task.run()
task.waitUntilExit()
return (task.terminationStatus, pipe)
}
extension Pipe {
func string() -> String? {
let data = self.fileHandleForReading.readDataToEndOfFile()
let result: String?
if let string = String(data: data, encoding: String.Encoding.utf8) {
result = string
} else {
result = nil
}
return result
}
}
重要的行以 try task.run()
开始并等待 task.waitUntilExit()