如何用异步任务装饰午睡请求

Posted

技术标签:

【中文标题】如何用异步任务装饰午睡请求【英文标题】:How to decorate Siesta request with an asynchronous task 【发布时间】:2018-06-25 17:46:00 【问题描述】:

在请求发生之前更改 Request 执行异步任务的正确方法是什么?

所以任何请求 Rn 都需要变成透明的 Tn 然后 Rn。

这里有一点背景:任务是一个第三方 SDK,它调度我需要用作原始请求的标头的令牌。

我的想法是装饰 Rn,但在此过程中我需要将我的 Tn 任务转换为 Siesta Request 然后我可以链接。

所以我包装了异步任务并链接到我的原始请求。 因此任何Rn 都会变成Tn.chained .passTo(Rn) 这样,这种新行为对整个应用程序来说是完全透明的。

问题

这样做我的代码最终会在 Siesta 内部前提条件下崩溃: precondition(completedValue == nil, "notifyOfCompletion() already called")

在我的自定义 AsyncTaskRequest 中,我收集成功、失败、进度等的回调,以便在 SDK 传递令牌时在主队列上触发它们。

我注意到一旦执行删除所有存储的回调,崩溃就消失了,但老实说我没有找到原因。

我希望有足够的信息来提供一些提示或建议。 提前谢谢你。

【问题讨论】:

【参考方案1】:

是的,实现 Siesta 的 Request 接口不是野餐。其他人有 exactly the same problem — 幸运的是 Siesta 版本 1.4 includes a solution。

新功能的文档仍然很薄。要使用新的 API,您将实现新的 RequestDelegate 协议,并将您的实现传递给 Resource.prepareRequest(using:)。这将返回一个您可以在标准 Siesta 请求链中使用的请求。结果将如下所示(警告 - 未经测试的代码):

struct MyTokenHandlerThingy: RequestDelegate 
  // 3rd party SDK glue goes here


...

service.configure(…) 
  if let authToken = self.authToken 
    $0.headers["X-Auth-Token"] = authToken  // authToken is an instance var or something
  

  $0.decorateRequests 
    self.refreshTokenOnAuthFailure(request: $1)
  


func refreshTokenOnAuthFailure(request: Request) -> Request 
  return request.chained 
    guard case .failure(let error) = $0.response,  // Did request fail…
      error.httpStatusCode == 401 else            // …because of expired token?
        return .useThisResponse                    // If not, use the response we got.
    

    return .passTo(
      self.refreshAuthToken().chained             // If so, first request a new token, then:
        if case .failure = $0.response            // If token request failed…
          return .useThisResponse                  // …report that error.
         else 
          return .passTo(request.repeated())       // We have a new token! Repeat the original request.
        
      
    )
  


func refreshAuthToken() -> Request 
  return Request.prepareRequest(using: MyTokenHandlerThingy())
    .onSuccess 
      self.authToken = $0.jsonDict["token"] as? String  // Store the new token, then…
      self.invalidateConfiguration()                    // …make future requests use it
    
  

要了解如何实现RequestDelegate,目前最好的办法是查看new API docs directly in the code。

由于这是一项尚未发布的全新功能,我非常感谢您报告它的工作原理以及您遇到的任何问题。

【讨论】:

这是个好消息!我没有遇到这个PR。我会尝试探索它。有 1.4 版本的 ETA 吗? 很遗憾,由于 Swift 4.1,我无法在此使用。我的项目很快就会迁移,但不是现在 :( 无论如何,我一直看到 authToken 的失败模式很好,但这不符合我的需要。(R -> Fail -> GetToken -> Success -> Invalidate -> R.Repeated ) 做 GetToken -> Success -> Invalidate -> R.Repeated 有什么陷阱吗?原因是:第 3 个 SDK 建议这种行为。令牌被 SDK 缓存并仅在实际需要时刷新。 是的,您描述的模式应该可以正常工作。请求链 API 的全部意义在于允许您设置任意重试路径,即我们的微型多请求状态机。一个可能的陷阱:要在您获得令牌后强制它重新读取配置,您可能需要执行request.repeated(),即使您从未启动过原始请求。 哦,根据 1.4 版本:ETA 是我一有时间完成文档并发布内务管理。 1.4 现已推出。

以上是关于如何用异步任务装饰午睡请求的主要内容,如果未能解决你的问题,请参考以下文章

如何用JAVA实现异步信息处理

Tornado异步与延迟任务

Python学习---Python的异步---asyncio模块(no-http)

我如何在异步任务中进行ksoap2调用?

任务Task系列之异步编程(async and await)

Spring Boot - 异步任务