Не подключается к серверу RP C в режиме выпуска, но отлично работает в режиме отладки - PullRequest
0 голосов
/ 07 мая 2020

У меня есть приложение командной строки, которое выполняет следующие действия:

  • загружает 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 (ссылка на конкретный c коммит с ошибкой)

1 Ответ

0 голосов
/ 11 мая 2020

Я попросил помощи на форумах Swift по телефону https://forums.swift.org/t/not-connecting-to-rpc-server-in-release-mode-but-works-fine-in-debug-mode/36251, и вот суть:

  • Ошибки отладки и выпуска распространены в экосистеме Apple.
  • Одна из частых причин вышеизложенного: компилятор имеет гораздо более агрессивные шаблоны сохранения и выпуска в режиме выпуска.
  • Моя проблема заключалась именно в том, что определенный класс удалялся раньше, чем следовало и это было точно отменяемым для подписки, поэтому мои запросы к серверу отменялись в середине.

Этот коммит исправляет это, и в основном он делает следующее:

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 явно исключает удаление объекта раньше, чем это должно было быть. Это определенное c местоположение - это то место, где я хотел избавиться от объекта, но не раньше.

...