2015-08-15 53 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

相關問題