使用多个dynos在Heroku上启动Play 2应用程序

3
我在Heroku上运行着一个Play 2.x应用,只有一个web dyno。
启动时,会触发一个Akka actor,它本身会安排未来的任务(例如发送推送通知)。
object Global extends GlobalSettings {

  override def onStart(app:Application) {
    val actor = Akka.system.actorOf(Props[SomeActor])
    Akka.system.scheduler.scheduleOnce(0 seconds, actor, None)
  }
}

这个方案对于一个web dyno来说运行良好,但是如果我增加了web dynos的数量,我很好奇会发生什么。

如果使用Global,它能否真正全局工作,并且onStart只被执行一次,无论有多少个web dynos,这将会很棒。如果不行,多个dynos必须就哪一个dyno负责完成任务达成共识。

有人遇到过类似的问题吗?


寻找解决方案。你最终的解决方案是什么? - Mik378
2个回答

5
如果您运行两个Web Dynos,那么您的全局变量将被执行两次。Global是进程级别的全局变量。当您扩展Web进程时,您实际上是在运行两个进程。您有几个选项:
  • 使用不同的进程(也称为单例进程)来运行您的全局变量。Play的好处是您可以拥有多个GlobalSettings实现。在启动进程时,您可以使用-Dapplication.global= YourSecondGlobal指定要使用的全局变量。然后,在procfile中,您需要这样写:singleton: target/start -Dhttp.port=${PORT} ${JAVA_OPTS} -Dapplication.global=YourSecondGlobal。启动Web进程和singleton进程,并确保仅有一个singleton进程。
  • 使用分布式信号量来获得锁。每个进程将竞争获取锁-赢家将继续执行,其他进程将失败。如果您正在使用Postgres(就像许多人在Heroku上做的那样),可以考虑使用advisory lock

感谢Naaman的好反馈!我之前不知道ProcFiles中有singleton,会尝试一下。 - Andreas
@Naaman,这种解决方案会不会导致你失去一个网络动力?因为单例无法处理HTTP请求(因为只有名称中包含“web”的动力才能处理)。 - Mik378
@Mik378 不,单例充当工作器。也许让人困惑的是示例包括 -Dhttp.port,也许它不需要(还没有测试是否必要)。 - Naaman Newbold
@Naaman 想象一下初始配置有两个购买的web dynos。当前的Procfile应该是:web: target/start -Dhttp.port=${PORT} ${JAVA_OPTS}。现在,如果我将这行代码添加到我的Procfile中:singleton: target/start -Dhttp.port=${PORT} ${JAVA_OPTS} -Dapplication.global=YourSecondGlobal并将进程缩放到最大值为1个dyno,使用heroku ps:scale singleton=1,那么我会得到多少个web dynos?仍然是2 + 1个worker(singleton)吗?还是一个会被替换为作为worker的singleton进程,导致1个web和1个worker? - Mik378
1
你将会有两个Web进程和一个单例进程。你可以在一个分开的应用中测试它,通过输入“heroku ps”来查看这些进程。 - Naaman Newbold

2

您还可以在运行时获取Dyno名称:

String dyno = System.getenv("DYNO");

因此,像这样进行检查也可能有效:

if(dyno.equals("web.1")) {

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接