加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

斯卡拉 – 获得或创造儿童阿卡演员并确保活力

发布时间:2020-12-16 18:52:38 所属栏目:安全 来源:网络整理
导读:我试图使用Akka actor的层次结构来处理每个用户状态.有一个拥有所有子节点的父actor,并以正确的方式处理get-or-create(参见 a1,a2): class UserActorRegistry extends Actor { override def Receive = { case msg@ DoPerUserWork(userId,_) = val perUserAc
我试图使用Akka actor的层次结构来处理每个用户状态.有一个拥有所有子节点的父actor,并以正确的方式处理get-or-create(参见 a1,a2):

class UserActorRegistry extends Actor {
  override def Receive = {
    case msg@ DoPerUserWork(userId,_) =>
      val perUserActor = getOrCreateUserActor(userId)
      // perUserActor is live now,but will it receive "msg"?
      perUserActor.forward(msg)
  }

  def getOrCreateUserActor(userId: UserId): ActorRef = {
    val childName = userId.toActorName
    context.child(childName) match {
      case Some(child) => child
      case None => context.actorOf(Props(classOf[UserActor],userId),childName)
  }
}

为了回收内存,UserActors在一段空闲时间后到期(即计时器触发子actor调用context.stop(self)).

我的问题是我认为我在“getOrCreateUserActor”和接收转发消息的子actor之间存在竞争条件 – 如果子进程在该窗口中到期,则转发的消息将丢失.

有什么方法可以检测到这种边缘情况,或重构UserActorRegistry以排除它?

解决方法

我可以看到你当前设计的两个问题,让你自己达到你提到的竞争条件:

1)终止条件(计时器发送毒丸)直接进入儿童演员.通过采用这种方法,子进程当然可以在一个单独的线程上(在调度程序内)终止,同时,已经设置了一条消息,在UserActorRegistry actor中(在调度程序内的另一个线程上)转发给它.

2)使用PoisonPill终止孩子. PoisonPill用于正常停止,允许首先处理邮箱中的其他邮件.在您的情况下,由于不活动而终止,这似乎表明邮箱中已有其他邮件.我在这里看到PoisonPill是错误的,因为在你的情况下,可能会在PosionPill之后发送另一条消息,并且在处理PoisonPill之后该消息肯定会丢失.

因此,我建议您将非活动子项的终止委托给UserActorRegistry,而不是在子项本身中进行.当您检测到不活动状态时,向UserActorRegistry实例发送一条消息,指示需要终止特定子项.当您收到该消息时,请通过停止而不是发送PoisonPill来终止该子项.通过使用以串行方式处理的UserActorRegistry的单个邮箱,您可以帮助确保在您要向其发送消息时不会并行终止子节点.

现在,这里有一个复杂的问题,你必须处理.停止一个actor是异步的.因此,如果您对子进程调用stop,则在处理DoPerUserWork消息时可能无法完全停止,因此可能会向其发送一条消息,因为它正在停止.您可以通过保留一些表示正在停止的子项的内部状态(List)来解决此问题.当您停止孩子时,将其名称添加到该列表,然后在其上设置DeathWatch(通过上下文监视子项).当您收到该孩子的终止事件时,请从被终止的孩子列表中删除它的名称.如果您的名字在该列表中时为您的孩子收到工作,请将其重新排队以进行重新处理,最多可能达到最大次数,以免永远尝试重新处理.

这不是一个完美的解决方案;它只是对您的方法的一些问题的识别,并推动正确的方向来解决其中的一些问题.如果你想看到这个的代码,请告诉我,我会把东西放在一起.

编辑

回应你的第二条评论.我不认为你能看到一个孩子的ActorRef并且看到它正在关闭,因此需要关闭正在关闭的子列表.您可以增强DoPerUserWork消息以包含numberOfAttempts:Int字段并将其递增并发送回self以进行重新处理(如果您看到目标子节点当前正在关闭).然后,您可以使用numberOfAttempts来防止永久重新排队,在某些最大尝试次数停止.如果您觉得依赖DeathWatch感觉不太舒服,可以在关闭子项列表中的项目中添加生存时间组件.然后你可以在遇到它们时修剪项目,如果它们在列表中但在那里已经存在太久了.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读