openai-kit icon indicating copy to clipboard operation
openai-kit copied to clipboard

There's no way to use a background session to make Chat requests

Open mumme opened this issue 1 year ago • 0 comments

Using a background session prevents Chat requests from failing if the app goes to background. The extension on URLSession uses dataTask with completionHandler, creating an exception:

    func dataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTaskProtocol {
        dataTask(with: request, completionHandler: completionHandler) as URLSessionDataTask
    }

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Completion handler blocks are not supported in background sessions. Use a delegate instead.'

One way to fix this issue is to save an array of continuations, use downloadTask and expose a way to send the URLSession configuration so we can set a delegate an control downloads:

    extension OpenAIService: URLSessionDownloadDelegate {
          func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
               guard let data = try? Data(contentsOf: location) else {
               continuations[downloadTask]?.resume(throwing: OpenAIServiceError.errorRequestingPrompt)
               return
            }
          continuations[downloadTask]?.resume(returning: data)
          continuations[downloadTask] = nil
        }
    }

    private lazy var backgrounUrlSession: URLSession = {
        let config = URLSessionConfiguration.background(withIdentifier: "com.mumme.fanart.openai")
        config.sessionSendsLaunchEvents = true
        config.shouldUseExtendedBackgroundIdleMode = true
        return URLSession(configuration: config, delegate: self, delegateQueue: nil)
    }()

    var continuations = [URLSessionTask: CheckedContinuation<Data, Error>]()

    func task(for request: URLRequest) async throws -> Data {
        try await withCheckedThrowingContinuation { continuation in
            let downloadTask = backgroundSession.downloadTask(with: request)
            continuations[downloadTask] = continuation
            downloadTask.resume()
        }
    }

mumme avatar Jul 11 '23 20:07 mumme