Swift 信号量行为

Swift semaphore behavior

我有问题。我需要一个可以使用的资源。我已经实现了这个机制:

func shouldRetry(request: Request, error: Error) -> Bool {
            let semaphore = DispatchSemaphore(value: 0)
            
            var shouldRetry: Bool = false
            self.interceptor?.retry(request.response, for: self.session!, dueTo: error, completion: { (retryResult) in
                switch retryResult {
                case .retry:
                    shouldRetry = true
                    semaphore.signal()
                case .doNotRetry:
                    shouldRetry = false
                    semaphore.signal()
                case .retryWithDelay(let delay):
                    shouldRetry = true
                    self.retryTimer = Timer.scheduledTimer(withTimeInterval: delay, repeats: false, block: { (_) in
                        semaphore.signal()
                        self.retryTimer?.invalidate()
                        self.retryTimer = nil
                    })
                }
            })
            
            semaphore.wait()
            return shouldRetry
        
    }

问题是interceptor?.retry func use在semaphore的同一个线程中被调用,这会阻塞进程。有什么建议吗?

更新:

我的问题解决了。我子 classes URLProtocol 摘要 class。 class 与 URLSession 一起工作,可以暂停 HTTP 调用,生成异步代码并恢复

我认为没有更多上下文就没有答案。但是,如果你尝试实现一个“refresh-token适配器/重试器”,策略如下:

您需要一个专门的适配器(结构或 class),它使用访问令牌设置授权 header。访问令牌必须是 thread-safe,甚至获取令牌也可能会失败 - 例如,因为有 none。如果出现错误,适配器将尝试不获取新的访问令牌,这将在重试器中完成。适配器可能只是不设置访问令牌。请求将失败,将在重试器中处理。

适配器调度是专用 queue 上的函数,我们称它为“process_queue”。完成 header 设置后,它会调用完成处理程序。

您还需要一个专门的 Retrier(结构或 class)。它访问保存令牌请求结果的共享状态。例如,这可以是 Swift.Result。

此重试器的函数在专用分派上执行 queue。

专门的 Retrier 确定响应状态,如果状态代码是 401(未授权)并且如果授权 header 是不记名令牌,则它需要发出 refresh-token 请求。

启动此 refresh-token 任务时,它会暂停 process_queue,以便不再使用过期的访问令牌进行请求调整。

现在,令牌请求完成并表示它已成功。重试器存储访问令牌(到钥匙链中),用新的访问令牌更新原始请求,然后 resumes process_queue 然后它调用它的完成处理程序。

适当的错误处理会使这稍微复杂一些。问题是当 refresh-token 请求失败时如何处理挂起的请求。我使用了一种方法,让所有 queued 的未决请求失败,直到 refresh-token 请求完成。他们只是失败并显示错误 401。然后开始新的循环,从尝试获取新的 refresh-token.

开始

这种方法可以防止多个失败的请求同时调用令牌端点。您甚至可以在刷新令牌也过期时扩展该方法。在这种情况下,您需要 sign-in 用户。这一切都可能发生在重试器内部。它仅在 sign-in 完成后、获取新的访问令牌完成后或发生错误时才完成。