生命周期確實是基礎結構的一個關注。應用程序很少需要接觸, 甚至不知道系統的生命周期。系統組件、管理控制臺, 或者需要長時間進行初始化并且需要在系統可用之前完全初始化的應用程序組件或actor, 這就必須知道系統生命周期。后者包括緩存控制器、緩存加載器、設備初始化,等等。
squbs運行時暴露了一下生命周期狀態:
- Starting - squbs啟動時的初始化狀態。
- Initializing - Unicomplex已啟動。服務啟動中。Cubes啟動中。等待初始化報告。
- Active - 準備好工作和服務調用。
- Failed - Cubes沒有正確啟動。
- Stopping - Unicomplex收到GracefulStop消息。終止cube,actor并解綁服務。
- Stopped - squbs運行停止。Unicomplex已終止。 ActorSystem已終止。
生命周期掛鉤
多數actor不關心它們什么時候啟動或者關閉。然而,可能有一類actor需要執行某些初始化, 然后才能到達接受常規通信的狀態。同樣地, 某些actor也關心在關閉之前被通知, 在送它們毒丸之前讓它們正確地清理。生命周期掛鉤正是出于這個原因。
可以讓你的actor注冊生命周期事件,通過發送ObtainLifecycleEvents(states: LifecycleState)給Unicomplex()*。一旦系統狀態改變,你的actor將受到生命周期狀態。
你也可以通過向Unicomplex()發送SystemState獲取當前狀態。你可以得到上面狀態的一種的響應。所有的系統狀態繼承于org.squbs.unicomplex.LifecycleState,并且都是org.squbs.unicomplex包的一部分,如下所示:
case object Starting extends LifecycleState
case object Initializing extends LifecycleState
case object Active extends LifecycleState
case object Failed extends LifecycleState
case object Stopping extends LifecycleState
case object Stopped extends LifecycleState
啟動掛鉤
希望參與初始化的actor 必須在 squbs 元數據META-INF/squbs-meta.conf中注明如下:
cube-name = org.squbs.bottlecube
cube-version = "0.0.2"
squbs-actors = [
{
class-name = org.squbs.bottlecube.LyricsDispatcher
name = lyrics
with-router = false # Optional, defaults to false
init-required = true # Tells squbs we need to wait for this actor to signal they have fully started. Default: false
}
init-required設置為true的任何actor需要發送Initialized(report)消息給cube監管者(是這些 well known actor的父母actor)。Try[Option[String]]類型的報告允許actor報告初始化的成功或者失敗(帶有異常信息)。一旦所有的cube初始化成功,squbs將變更為Active狀態。這也意味著每個init-required設為true的actor提交了成功信息的Initialized(report)。如果任何一個cube通過Initialization(report)報告了初始化錯誤,squbs將以Failed狀態終結。
關閉掛鉤
停止actor
org.squbs.lifecycle.GracefulStopHelper特質讓用戶獲得優雅停止他們actor的代碼。你可以在你的actor中混入這個特質,用下面的方法。
class MyActor extends Actor with GracefulStopHelper {
...
}
該特質提供了一些輔助方法來支持 Squbs 框架中的actor的優雅停止。
停止超時
StopTimeout
/**
* Duration that the actor needs to finish the graceful stop.
* Override it for customized timeout and it will be registered to the reaper
* Default to 5 seconds
* @return Duration
*/
def stopTimeout: FiniteDuration =
FiniteDuration(config.getMilliseconds("default-stop-timeout"), TimeUnit.MILLISECONDS)
你可以重寫該方法, 以指示此actor需要執行優雅停止大概多長時間。一旦actor啟動, 它將發送 stopTimeout (stopTimeout) 消息給其父。如果您關心此消息, 則可以讓父actor處理此消息。
如果你在actor代碼中混入了這個特質,你應當在接收方法中處理GracefulStop消息,因為只有這種情況下你可以掛鉤你的代碼到執行一個優雅的停止(你不可以對PoisonPill證件自定義行為)。監管者只傳播GracefulStop消息給混入了GracefulStopHelper特質的孩子。孩子的實現應當在它們的接收代碼中處理這個消息。
我們還提供了特質中以下2個默認策略。
/**
* Default gracefully stop behavior for leaf level actors
* (Actors only receive the msg as input and send out a result)
* towards the `GracefulStop` message
*
* Simply stop itself
*/
protected final def defaultLeafActorStop: Unit = {
log.debug(s"Stopping self")
context stop self
}
/**
* Default gracefully stop behavior for middle level actors
* (Actors rely on the results of other actors to finish their tasks)
* towards the `GracefulStop` message
*
* Simply propagate the `GracefulStop` message to all actors
* that should be stop ahead of this actor
*
* If some actors failed to respond to the `GracefulStop` message,
* It will send `PoisonPill` again
*
* After all the actors get terminated it stops itself
*/
protected final def defaultMidActorStop(dependencies: Iterable[ActorRef],
timeout: FiniteDuration = stopTimeout / 2): Unit = {
def stopDependencies(msg: Any) = {
Future.sequence(dependencies.map(gracefulStop(_, timeout, msg)))
}
stopDependencies(GracefulStop).onComplete({
// all dependencies has been terminated successfully
// stop self
case Success(result) => log.debug(s"All dependencies was stopped. Stopping self")
if (context != null) context stop self
// some dependencies are not terminated in the timeout
// send them PoisonPill again
case Failure(e) => log.warning(s"Graceful stop failed with $e in $timeout")
stopDependencies(PoisonPill).onComplete(_ => {
// don't care at this time
if (context != null) context stop self
})
})
}
停止squbs擴展
你可以在擴展關閉里增加自定義行為,通過覆蓋org.squbs.lifecycle.ExtensionLifecycle的shutdown()方法。請注意, 在所有已安裝的擴展中, 此方法將在actor系統終止后執行。如果任何擴展在關閉期間拋出異常, JVM 將以-1退出。