原文地址:Runtime Lifecycle & API
生命周期是一个真正需要关注的基础。应用程序很少接触或感知到系统的生命周期。系统组件、管理员控制台、应用组建、actors会经过很长一段时间的初始化,并且为了traffic了解系统生命周期,系统必须在可用前完全初始化。后面包括诸如控制器(controller)、缓存加载器(cache loaders)、设备初始化器等等。
squbs运行时暴露以下生命周期状态:
Starting - squbs启动时的状态
Initializing - Unicomplex已启动. Services启动中. Cubes启动中. 等待初始化报告.
Active - 准备工作和执行服务调用
Failed - Cube可能没有启动
Stopping - Unicomplex收到GracefulStop消息 停止cube, actor, 和未绑定的service.
Stopped - 运行中的squbs已停止. Unicomplex终止. ActorSystem终止.
生命周期钩子(Hooks)
大多数的actor不关心他们什么时候启动或者停止。然而,他们可能为同一类actor,在他们达到接收一般trafiic状态前需要初始化。同样的,一些actor同样关心在关闭前被通知到,以允许在发送他们毒药丸(poison pill)之前适当的清理。生命周期的钩子存在就是为了这个原因。
你可以通过发送ObtainLifecycleEvents(状态: LifecycleState*)
至Unicomplex()
将你actor注册到生命周期事件中。一旦系统的状态改变,你的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
启动钩子(Hooks)
一个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 # 告知squbs我们需要在发送所有已经启动前等待该actor
}
任何设置init-required为true的actor需要发送一个已完成(报告)消息至cube管理者,即这些well known actor的父actor。这个报告是Try[Option[String]]
类型,允许actor报告初始化成功和失败(可能携带异常)。一旦所有的cube成功的初始化完成,运行中的squbs转变至Active 状态。这同样表示每个设置init-required为true的actor提交了初始化成功的报告。如果任何cube报告一个初始化失败的报告,运行中的squbs会以一个Failed状态取而代之。
关闭钩子(Hooks)
停止Actors
特性org.squbs.lifecycle.GracefulStopHelper
让用户在他们自己的代码中实现优雅的关闭actor。你可以按如下的方式在你的actor中混合(mix)这个特性(trait):
scala
class MyActor extends Actor with GracefulStopHelper {
...
}
这个特性提供了一些帮助方法来支持在squbs框架中优雅的关闭actor
StopTimeout
scala
/**
* 优雅的关闭actor的超时时间
* 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)
消息将stopTimeout
发送至它们的父节点。如果你关心它,你可以在父actor中处理这条信息。
如果你混合(mix)这个特性在你的actor代码中,你应该在你的receive
方法中接收GracefulStop
消息,因为只有在这种情况下你可以勾住你的代码来执行一个优雅的停止(你无法向PoisonPill
添加自定义行为)。管理者将仅仅传播 GracefulStop
消息至他们那些混合了GracefulStopHelper
特性的子节点。子节点的实现应该在他们的receive
块中处理这个消息。
我们还提供了以下两个默认策略:
/**
* 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退出。