在发布模式下未连接到RPC服务器,但在调试模式下运行良好



我有一个命令行应用程序,它可以执行以下操作:

  • 下载带有torrent链接的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中提供的完整代码(链接到有错误的特定提交(

我在Swift论坛上寻求帮助https://forums.swift.org/t/not-connecting-to-rpc-server-in-release-mode-but-works-fine-in-debug-mode/36251要点如下:

  • 调试与发布错误在苹果生态系统中很常见
  • 出现上述情况的一个常见原因是:编译器在发布模式下具有更积极的保留和发布模式
  • 我的问题正是这样:某个类被提前处理,而且它正是订阅的可取消类,所以我的服务器请求在在中间被取消了

这个提交修复了它,它基本上完成了以下操作:

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 {

调用cancellable显式地避免了对象在应该处理之前被处理掉。那个特定的位置是我打算处理这个物体的地方,而不是更早。

最新更新