来自Future回调中的Akka长时间运行初始化和崩溃的actor

时间:2015-04-03 22:31:57

标签: scala akka

我有一个负责与网络服务交谈的演员。我命令与服务交谈,演员需要获取授权令牌。令牌定期到期,因此演员还需要定期检查令牌是否已过期并获取新令牌。

我的问题:

在构造函数中执行可能失败的长期运行任务的可接受方法是什么?在我的例子中,在成功从远程服务接收到令牌之前,我的演员不能被认为是“准备好”。这可能会失败,应该重新尝试。

我应该如何处理服务无法访问的情况,阻止我获取新令牌。我想抛出一个由我的主管策略处理的异常(某种限制的重启政策)

这基本上就是我现在所拥有的:

case object CheckAuth
case object AuthFailed
case class UpdateAuth(token: Token)

var auth: Token = Await.result(authorize(), 2.seconds) // throws if server cannot be reached or i'm denied

val tick = scheduler.schedule(10.seconds, 10.seconds, self, CheckAuth)
override def postStop = tick.cancel()

override def receive: Receive = {
  case AuthFailed    => throw new Exception("Auth failed")
  case UpdateAuth(a) => auth = a
  case CheckAuth => {
    if ( authHasExpired() ) {
      authorize() onComplete {
        case Success(r) => self ! UpdateAuth(r)
        case Failure(e) => self ! AuthFailed // this feels dirty
      }
    }
  }
}

1 个答案:

答案 0 :(得分:2)

对此进行建模的正确方法是为Actor提供两种状态,无论是显式还是隐式。它们之间的选择取决于客户与此Actor的交互方式如下:

  • 当没有令牌可用时,Actor会回应请求,或者
  • 在没有令牌的情况下,Actor会存储请求,并在有可用时回答。

显式模型使用context.become()

class A extends Actor with Stash {
  def auth(): Unit = {
    authorize() pipeTo self
    context.system.scheduler.scheduleOnce(2.seconds, self, AuthTimeout)
  }
  def update(token: AuthToken): Unit = {
    context.become(running(token))
    context.system.scheduler.scheduleOnce(10.seconds, self, CheckAuth)
  }

  auth()

  def receive = initial
  val initial: Receive = {
    case UpdateAuth(token) =>
      unstashAll()
      update(token)
    case AuthTimeout => context.stop(self)
    case _ => stash()
  }
  def running(token: AuthToken): Receive = {
    case CheckAuth => auth()
    case AuthFailed => context.become(initial)
    case UpdateAuth(token) => update(token)
    ...
  }
}

隐式模型在Actor中存储var token: Option[AuthToken],从无。

开始

关于故障的处理:你可以做任何你想做的事情,我建议停止演员并让主管在给定的时间重启之后重新创建它,因为supervisorStrategy总是立即。