3

我们目前正在我的团队中进行讨论,我会对其他观点感兴趣。假设我们有一个 RESTful Web 服务,其作用是通过应用各种分析算法和服务来注释文档。清晰的基本交互:我们有一个资源,即文档集合;客户端向集合发布一个新文档,获取新文档的 URI,然后可以 GETdocURI以获取文档或 GET{docURI}/metadata以查看一般元数据,{docURI}/ne对于命名实体等。问题是一些分析可能需要很长时间才能完成。假设客户端在分析完成之前获取元数据 URI,因为它希望能够在 UI 中显示部分或增量结果。将来重复 GET 可能会产生更多结果。

我们讨论过的解决方案包括:

  • 保持 HTTP 连接打开直到所有分析完成(这似乎不可扩展)
  • 使用 content-lengthand accept-range headers 获取增量内容(但我们事先不知道最终内容会持续多长时间)
  • 为每个资源提供一个 Atom 提要,以便客户端订阅更新事件而不是简单地获取资源(如果有许多活动文档,似乎过于复杂并且可能资源匮乏)
  • 只是让 GET 返回当时可用的任何内容(但它仍然留下客户端知道我们何时完成的问题)[编辑以删除对幂等性的引用以下评论]

对于在 RESTful 架构中处理长期或异步交互的替代方法有什么意见或建议?

伊恩

4

7 回答 7

3

我将通过以下方式实现它:

1) 客户端请求元数据
2) 服务器返回实际数据(如果它已经可用)或 NotReady 标记
3) 客户端询问服务器何时数据可用(此步骤可以与上一步合并)
4) 服务器返回时间间隔(可能有执行作业总数的一些启发式等)
5)客户端等待指定的时间段并转到步骤1

这样您就可以尽快向客户提供数据。您可以通过调整第 4 步返回的延迟间隔来调整服务器负载)

于 2008-09-23T10:16:25.510 回答
3

为每个资源提供一个 Atom 提要,以便客户端订阅更新事件而不是简单地获取资源(如果有许多活动文档,似乎过于复杂并且可能资源匮乏)

你考虑过SUP吗?

如果轮询是一种选择,为什么还要麻烦提要?为什么不让客户轮询资源本身呢?

您能否通过包括完成分析的估计时间来减少不必要的轮询?

于 2008-09-23T10:18:59.030 回答
2

使用HTTP 202 接受

此外,请查看RESTful Web 服务- 这是我了解上述内容的地方。

于 2008-09-23T10:42:13.327 回答
2
  • 只是忽略幂等性并让 GET 返回当时可用的任何内容(但它仍然留下客户端知道我们何时最终完成的问题)。

随着时间的推移返回不同结果的 GET 真的意味着它不是幂等的吗?规范说:

方法还可以具有“幂等性”的属性,因为(除了错误或过期问题)N > 0 相同请求的副作用与单个请求相同

也就是说,对 GET 的多次调用可能会返回不同的结果,只要调用本身没有副作用。

在这种情况下,也许您的 REST 方法可以使用条件 GET 和缓存机制来指示何时完成:

  • 在分析过程中,GET {docURI}/metadata响应可能有:
    • 标题设置为Expires未来几秒钟。
    • 没有ETag标题。
  • 分析完成后,对该资源的响应具有:
    • 没有Expires标题。
    • 一个ETag。带有 的后续请求ETag应该返回304 Not Modified

注意,您可能需要考虑缓存中涉及的其他响应标头,而不仅仅是 Expires。

这种“感觉”就像一个 RESTful 设计——您可以想象一个 Web 浏览器在向该资源发出连续请求时做正确的事情。

于 2008-09-23T11:02:23.480 回答
1

You may want to check out Udi Dahan's nServiceBus.

于 2008-09-26T13:38:59.980 回答
1

“让 GET 返回当时可用的任何东西”很有意义。除了,当他们进行投票时,你不想继续返回他们已经知道的东西。每次投票时,答案都会变长。

您需要他们在 GET 请求中为您提供他们的“到目前为止我所看到的”。这给了你幂等性。如果他们要求块 1,他们总是得到相同的答案。一旦他们看到了块 1,他们就可以请求块 2。

答案不会变得更大。更多作品可用。“集合级” GET 提供响应的大小。对于每个可用的部分,您都有“详细级别”的 GET。

本质上,这是一种类似于 TCP/IP 确认的算法。当他们确认一块时,您发送下一块。如果有下一篇,否则你发送一个200-nothing new 来报告。

“客户知道我们何时最终完成的问题”是不可估量的。他们不知道,你也无法预测需要多长时间。

您不希望他们“忙于等待”——轮询以查看您是否完成了——这对您的服务器来说是一个相当大的负载。如果他们不耐烦。您可以限制他们的请求。您可以向他们发送“x 秒后返回检查”,其中 x 会逐渐变大。

您甚至可以使用 Unix 风格的调度程序算法,当他们轮询时他们的分数下降,如果他们不轮询 X 秒,他们的分数就会上升。

另一种选择是某种队列,您可以将结果发回给他们。为此,他们必须提供一个 URI,您可以通过 POST 告诉他们您已完成。

或者,他们将 Atom 用于轻量级轮询架构。虽然 Atom 看起来很复杂——它仍然涉及轮询——你提供一个最小的 Atom 答案(“尚未更改”)直到你完成,当你提供(“新结果”)时,他们可以做真正的重量级得到。这是全有或全无,而不是上面的增量响应技术。

您还可以将“集合级”GET 视为您在整个流程中的 Atom 状态。

于 2008-09-23T22:10:28.710 回答
1

一种可能适合也可能不适合您的情况的替代解决方案是添加一个名为“AnnotationRequests”的新端点。将文档(或指向它的链接)发布到 AnnotationRequests 端点,它应该返回一个位置(例如http://example.org/AnnotationRequest/2042),这将允许您的客户端轮询进程的状态。当该过程完成时,“AnnotationRequest”表示可以包含到已完成文档的链接。

这样做的一个很好的副作用是您可以在 AnnotationRequests 上执行 GET,以便查看当前正在处理的文档。由您决定要将 AnnotationRequests 保留多长时间。保留完整的历史记录可能很有价值,包括请求的时间、请求的对象和请求的时间,或者可以定期丢弃它们。

于 2008-09-24T13:05:12.007 回答