【问题标题】:Shell command via NSTask's Process delayed until my Vapor app quits通过 NSTask 进程的 Shell 命令延迟到我的 Vapor 应用程序退出
【发布时间】:2021-11-16 21:38:32
【问题描述】:

我构建了一个 Vapor 4 应用程序,该应用程序当前部署在本地 Ubuntu 18 服务器 VM 上,在 NGINX 后面运行并为用户提供服务,没有任何问题。

现在我希望我的 Web 服务器路由之一通过 Process 执行 Bash 命令来响应特定的 POST (这是为了通过 @987654321 将消息发送到专用的 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](https://stackoverflow.com/a/43014767/3765705) 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 上那样发生:我没有 Vapor 记录的错误当我发布到该路线时,即使我等待一段时间,Slack 中也不会出现任何消​​息!

但这里有一个棘手的部分:一旦我在服务器上停止了我的 Vapor 应用程序,所有消息都会立即发送到 Slack

经过大量测试(其中显然包括使用在我的 Vapor 应用程序中传递给 NSTaskProcess 类的完全相同的命令,确认可以从服务器毫无延迟地发布到 Slack),似乎 Bash 命令没有执行直到我的 Vapor 应用退出

显然,我错过了如何使 Process 与 Vapor “实时”工作的一些内容,我将不胜感激能获得的所有帮助。

【问题讨论】:

    标签: swift vapor nstask


    【解决方案1】:

    您需要等到任务完成。看起来你自己陷入了僵局。这就是我在 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() 等待的重要行

    【讨论】:

    • 谢谢!而且你还教我@discardableResult,非常有用! ;)
    猜你喜欢
    • 2015-11-21
    • 1970-01-01
    • 1970-01-01
    • 2014-06-22
    • 1970-01-01
    • 2012-08-17
    • 2015-02-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多