11

Play 框架的一大优点是它是完全无状态的,并且只面向请求/响应。这真的很好,因为它允许我将我的应用程序部署到云并扩展负载均衡器后面的播放实例的数量,而不必担心状态(会话)复制......

然而,最近,我需要在 HTTP 请求之外执行一些应用程序逻辑,并发现 Play 可以定义完全由框架管理的作业。听起来很棒,但它提出了一个问题:这些工作如何适应 Play 使用的无状态模型?

假设我有一个需要每小时运行的维护任务,我为此定义了一个计划作业。如果我随后在负载均衡器后面部署多个 Play 实例,该作业是否会在每个实例上同时启动?如果是这样,处理需要“独占”运行的作业的好方法是什么?

我正在考虑在非集群服务器上创建一个新的播放实例,重新使用现有(集群)实例的 JPA 模型(从而连接到同一个数据库)。这个新实例将仅包含维护作业,并且由于它托管在非集群服务器上,因此不存在同时运行作业的风险。同时,这将使我能够保持现有的集群实例完全无状态并且易于托管/负载平衡。这是一个好方法吗?

4

3 回答 3

5

I would recommend to cluster the job too. You could set a semaphore in the database to ensure that only one job is running. Another idea is to have a look at the Akka-Framework, which will be included in Play 2.0. I think it has build in mechanism with handle this problem, but I'm not sure. I haven't experiences with akka.

于 2011-10-16T16:10:29.990 回答
5

正如尼尔斯提到的,在数据​​库中保留一个标志有助于找出作业是否已经在运行。我使用带有其他标志的 db 信号量来为我提供工作状态和额外信息。

您可以做的另一件事是使用 Play.id 来确定并定义应该运行作业的实例。我们在我的 doJob() 方法中使用“play start --%prod”、“play start --%prod1”... 来启动应用程序和以下内容:


doJob(){
   if ("prod".equalsIgnoreCase(Play.id)) {
   ...
   }
}
于 2011-10-17T05:55:22.630 回答
2

快速浏览了 Play 框架(类JobJobsPlugin)的源代码后,我认为这些不适合在集群环境中使用,因为重要的是作业仅在某个时间间隔运行一次(不引入丑陋的黑客攻击)。

我看到了三种可能的解决方案:

  1. 使用支持集群的作业调度程序。显而易见的选择是Quartz。Play 也使用Quartz 的一部分(解析 CRON 表达式),但不使用调度的部分。

  2. 使用 Play 2 时,可能会选择Akka,它提供了一个调度器。

  3. 更改您的工作,使其在运行两次时无关紧要(对于某些用例可能)。

于 2012-11-19T16:05:51.370 回答