2015-08-15 55 views
0

我有一个Play插件,执行每15分钟这样的方法:如何确保只有一个播放实例实际运行在一个特定时刻的方法

import scala.concurrent.Future 
import scala.concurrent.duration._ 
import play.api.libs.concurrent.Akka 
import play.api.libs.concurrent.Execution.Implicits.defaultContext 
import play.api.{Application, Plugin} 
import akka.actor.Cancellable 

class AuthPlugin(app: Application) extends Plugin { 

    private var cancellableDoSomething: Option[Cancellable] = None 

    ... 

    override def onStart = { 
    cancellableDoSomething = Some(
     Akka.system.scheduler.scheduleOnce(0.seconds) { 
     doSomething.foreach { _ => 
      Akka.system.scheduler.scheduleOnce(15.minutes)(doSomething) 
     } 
     } 
    ) 
    } 

    override def onStop = { 
    cancellableDoSomething.foreach(_.cancel) 
    } 
} 

object AuthPlugin { 

    ... 

    def doSomething: Future[Unit] = { 
    // Access to shared DB here... 
    } 
} 

让我们假设我有我的Play两个实例应用程序运行在两台不同的主机上,每台主机每15分钟调用一次doSomething

如何确保只有一个实例在某个特定时刻实际运行doSomething

编辑

两个Play实例访问同一个数据库,并doSomething进程状态pending记录。在处理完状态为pending的记录后,它会更新为状态processed

如果第一Play实例查询数据库挂单并在处理他们的第二Play实例中运行相同的查询时,其获得的是还包括挂起已经由第一Play例如查询订单,但尚未处理的记录集。为避免这种情况,当且仅当没有其他正在执行它的实例时,实例才能调用doSomething

我可以实现了一种基于DB-信号的地方获取第一Play例如,它字段的值设置为1或任何其他...但因为如果Play实例失败这种解决方案并不稳定,从来没有将字段设置为0,然后其他Play实例不再能够获取信号量并调用doSomething

+0

我假设你有一个共享资源问题。你能描述你想要达到的目标吗? – Aaron

+0

由于每个游戏应用都运行在不同主机上的独立JVM上,因此您有两种选择:使用某些外部服务进行同步或自行实现此类同步,例如在Akka – maks

+0

的帮助下创建nfs数据库机器共享创建文件并使用男人2在它上面 – ayvango

回答

0

使用其中更新过程中提供了特定操作,例如锁定机构的数据库
实施例:MySQL

“MySQL使用行级锁定InnoDB表”

“MySQL使用MyISAM,MEMORY和MERGE表的表级锁定”


这意味着您可以使用上述任何一个表获得锁定机制。


锁定处理

1.让你的机器希望去努力工作。比方说,你得到一个与jobId=123

2.尝试原子锁定。

UPDATE jobs SET state='started' and worker='worker1' WHERE jobId=123 AND state='pending'; 


3.检查锁收购将通过机械'worker1'收购。

SELECT COUNT(*) FROM JOBS where jobId=123 AND state='started' AND worker='worker1'; 


4.如果上面的查询返回1,然后'worker1'已经成功地保留了工作,给所有其他机器排除。如果查询返回0,这意味着某个其他机器(例如'worker2')首先获得该锁。

当作业完成

UPDATE jobs SET state='finished' WHERE jobId=123;<br> 


如果保留机器出现故障怎么办?

尝试锁定(通过UPDATE)时,还要添加一个时间戳列。然后,让另一个后台工作定期清理比1小时更早但国家仍然“开始”的工作。

+0

是的......这或多或少是我心中所想......除了我使用MongoDB。无论如何。 – j3d

相关问题