簡體   English   中英

在發布模式下無法連接到 RPC 服務器,但在調試模式下工作正常

[英]Not connecting to RPC server in release mode, but works fine in debug mode

我有一個命令行應用程序,它執行以下操作:

  • 下載帶有種子鏈接的 RSS 提要
  • 將其存儲在 sqlite 數據庫中,並將它們標記為“已添加”或“已忽略”
  • 連接到傳輸服務器(在我的本地網絡中)
  • 從標記為“已添加”的 sqlite 加載項目並添加到傳輸服務器

以上在調試模式下工作正常。 但是,當我為發布構建並嘗試直接運行或從 launchd 運行時,它總是超時。 最相關的代碼在下面的main.swift中。

private func getTransmissionClient() -> Transmission? {
        let client = Transmission(
            baseURL: serverConfig.server,
            username: serverConfig.username,
            password: serverConfig.password)

        var cancellables = Set<AnyCancellable>()

        let group = DispatchGroup()
        group.enter()
        print("[INFO] Connecting to client")
        client.request(.rpcVersion)
            .sink(
                receiveCompletion: { _ in group.leave() },
                receiveValue: { rpcVersion in
                    print("[INFO]: Successfully Connected! RPC Version: \(rpcVersion)")
            })
            .store(in: &cancellables)
        let wallTimeout = DispatchWallTime.now() +
            DispatchTimeInterval.seconds(serverConfig.secondsTimeout ?? 15)
        let res = group.wait(wallTimeout: wallTimeout)

        if res == DispatchTimeoutResult.success {
            return client
        } else {
            return nil
        }

    }

    public func updateTransmission() throws {

        print("[INFO] [\(Date())] Starting Transmission Update")

        let clientOpt = getTransmissionClient()
        guard let client = clientOpt else {
            print("[ERROR] Failed to connect to transmission client")
            exit(1)
        }

        var cancellables = Set<AnyCancellable>()

        let items = try store.getPendingDownload()
        print("[INFO] [\(Date())] Adding \(items.count) new items to transmission")

        let group = DispatchGroup()
        for item in items {

            let linkComponents = "\(item.link)".components(separatedBy: "&")
            assert(linkComponents.count > 0, "Link seems wrong")

            group.enter()
            client.request(.add(url: item.link))
                .sink(receiveCompletion: { completion in
                    if case let .failure(error) = completion {
                        print("[Failure] \(item.title)")
                        print("[Failure] Details: \(error)")

                    }
                    group.leave()
                }, receiveValue: { _ in
                    print("[Success] \(item.title)")
                    do {
                        try self.store.update(item: item, with: .downloaded)

                    } catch {
                        print("[Error] Couldn't save new status to DB")
                    }
                })
                .store(in: &cancellables)
        }


        let wallTimeout = DispatchWallTime.now() +
            DispatchTimeInterval.seconds(serverConfig.secondsTimeout ?? 15)
        let res = group.wait(wallTimeout: wallTimeout)
        if res == DispatchTimeoutResult.success {
            print("Tasks successfully submitted")
        } else {
            print("Timed out")
            exit(1)
        }
    }

奇怪的是,在我添加數據庫之前,代碼似乎運行良好。 DispatchGroup 以及 Transmission-Swift 客戶端已經存在。 我猜我所做的事情是被編譯器“優化掉”了? 這只是猜測,雖然在 StackOverflow 上看到了其他一些問題,但我仍然不清楚。

我正在使用 macOS 10.15 和 Swift 5.2.2。

github中可用的完整代碼(鏈接到有錯誤的特定提交)

我在https://forums.swift.org/t/not-connecting-mode-to-rpc-server-in-debug-mode-to-rpc-server-in-debug-mode-to-rpc-server-in-debug-mode-to-rpc-server-in-debug-mode-to-rpc-server-in-debug-mode-to-rpc-server-in-debug-mode-to-rpc-這是它的要點:

  • 調試與發布錯誤在 Apple 生態系統中很常見。
  • 上述原因的一個常見原因是:編譯器在發布模式下具有更激進的保留和釋放模式。
  • 我的問題正是如此:某個 class 比它應該更早地被處理掉了,它正是訂閱的可取消,所以我的服務器請求在中間被取消了。

提交修復了它,它基本上執行以下操作:

diff --git a/Sources/TorrentRSS/TorrentRSS.swift b/Sources/TorrentRSS/TorrentRSS.swift
index 17e1a6b..0b80cd5 100644
--- a/Sources/TorrentRSS/TorrentRSS.swift
+++ b/Sources/TorrentRSS/TorrentRSS.swift
@@ -63,6 +63,10 @@ public struct TorrentRSS {
             DispatchTimeInterval.seconds(serverConfig.secondsTimeout ?? 15)
         let res = group.wait(wallTimeout: wallTimeout)

+        for cancellable in cancellables {
+            cancellable.cancel()
+        }
+
         if res == DispatchTimeoutResult.success {
             return client
         } else {
@@ -117,6 +121,11 @@ public struct TorrentRSS {
         let wallTimeout = DispatchWallTime.now() +
             DispatchTimeInterval.seconds(serverConfig.secondsTimeout ?? 15)
         let res = group.wait(wallTimeout: wallTimeout)
+
+        for cancellable in cancellables {
+            cancellable.cancel()
+        }
+
         if res == DispatchTimeoutResult.success {
             print("Tasks successfully submitted")
         } else {

顯式調用可取消可避免 object 提前被處理掉。 該特定位置是我打算處理 object 的地方,而不是更早。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM