使用GWT和GAE的同步、异步和命令客户端请求



在设计我的GWT/GAE应用程序时,很明显,我的客户端(GWT)将生成三种类型的请求:

  • 同步-"立即回答我!我很重要,需要实时响应!!"
  • 异步-"尽可能回答我;我需要在某个时候知道答案,但实际上并不是那么简单。"
  • 命令-"我不需要答案。这不是一个真正的请求,它只是一个在服务器端做某事或处理某事的命令。"

我的游戏计划是实现我的GWT代码,这样我就可以为每个特定的服务器端请求指定(注意:由于这个问题范围之外的原因,我决定使用RequestFactory而不是传统的GWT-RPC),它是哪种类型的请求:

  • SynchronousRequest-同步(从上面开始);发送命令并急切地等待响应,然后以某种方式使用该响应来更新客户端的状态
  • AsynchronousRequest-异步(来自上面);发出初始请求,并以某种方式-通过轮询或GAE Channel API,在最终收到响应时得到通知
  • CommandRequest-命令(来自上方);发出服务器端请求而不等待响应(即使服务器未能或拒绝执行命令)

我想我使用SynchronousRequest的目的不是产生完全阻塞的请求,但它可能会阻塞用户与特定Widget或屏幕部分交互的能力。

这里增加的关键是:GAE在其所有前端实例上强制执行超时(60秒)。后端实例对超时、线程等的约束要宽松得多。因此,对我来说,AsynchronousRequestsCommandRequests应该路由到后端实例,这样GAE超时就不会成为它们的问题。

然而,如果GAE表现不佳,或者我们的流量达到峰值,或者我的代码非常糟糕,我必须考虑这样的情况,即生成SynchronousRequest(它必须经过一个受超时限制的前端实例),并且将超时,除非我的GAE服务器代码做了一些花哨的事情。我知道在GAE API中有一个方法,我可以调用它来查看一个请求在即将超时之前有多少毫秒;但是,尽管我现在记不起它的名字,但这正是这个"花哨"代码的基础。为了这个问题,我们称之为public static long GAE.timeLeftOnRequestInMillis()

在这种情况下,我想检测SynchronousRequest即将超时,并以某种方式将其动态转换为AsynchronousRequest,这样它就不会超时。也许这意味着将AboutToTimeoutResponse发送回客户端,并迫使客户端决定是作为AsynchronousRequest重新发送还是失败。或者,我们可以将SynchronousRequest转换为AsynchronousRequest,并将其推送到队列中,后端实例将在队列中使用、处理并返回响应。在实现方面,我没有任何偏好,只要请求不会失败或超时,因为服务器无法足够快地处理它(因为GAE强制的规定)。

那么,这就是我实际上在问的问题:

  • 如何将RequestFactory调用封装在SynchronousRequestAsynchronousRequestCommandRequest中,使RequestFactory调用的行为与它们各自的预期方式一致?换句话说,这样调用要么部分阻塞(同步),要么可以在以后的某个时间点被通知/更新(异步),要么只能是即发即弃(命令)
  • 我如何实现我的要求,让SynchronousRequest绕过GAE的60秒超时,仍然可以在不失败的情况下进行处理

请注意:通过将东西重新路由到后端实例,可以很容易地避免超时问题,但后端无法扩展。我在这里也需要可扩展性(这就是我最初使用GAE的主要原因!),所以我需要一个处理可扩展前端实例及其超时的解决方案。提前感谢!

如果您希望GAE进行的计算需要超过60秒,那么在发送响应之前不要等待计算结果。根据你对问题的定义,没有办法绕过这个问题。相反,客户端应该提交工作指令,并在结果准备好后等待服务器的通知。请求将由工作指令组成,可能看起来像这样:

class ComputeDigitsOfPiWorkOrder {
  // parameters for the computation
  int numberOfDigitsToCompute;
  // Used by the GAE app to contact the requester when results are ready.
  ClientId clientId;
}

这样,你的GAE应用程序可以在工作订单保存后立即响应(例如在任务队列中),并且不必等到它真正完成了十亿位数的圆周率计算后再响应。然后GWT客户端使用Channel API等待结果。

为了给某些工单更高的优先级,可以使用多个任务队列。如果您希望"任务队列"工作自动扩展,则需要使用推送队列。使用推送队列实现优先级有点棘手,但您可以将高优先级队列配置为具有更快的馈送速率。

您可以将Channel API替换为其他通知解决方案,但这可能是最直接的。

最新更新