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.

经过大量测试(这显然包括通过使用传递给 NSTaskProcess 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()