Scala Akka长期运行初始化并从未来回调中崩溃actor

Scala Akka长期运行初始化并从未来回调中崩溃actor,scala,akka,Scala,Akka,我有一个参与者负责与web服务对话。为了与服务对话,参与者需要获取授权令牌。令牌定期过期,因此参与者还需要定期检查令牌是否已过期,并获取新令牌 我的问题是: 对于在构造函数中可能失败的长时间运行的任务,什么是公认的方法?在我的示例中,在我的参与者成功地从远程服务接收到令牌之前,不能将其视为“就绪”。这可能会失败,应该重新尝试 我应该如何处理无法访问服务、阻止我获取新令牌的情况。我想抛出一个由我的主管策略(某种限制重启策略)处理的异常 这基本上就是我现在拥有的: case object Check

我有一个参与者负责与web服务对话。为了与服务对话,参与者需要获取授权令牌。令牌定期过期,因此参与者还需要定期检查令牌是否已过期,并获取新令牌

我的问题是:

对于在构造函数中可能失败的长时间运行的任务,什么是公认的方法?在我的示例中,在我的参与者成功地从远程服务接收到令牌之前,不能将其视为“就绪”。这可能会失败,应该重新尝试

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

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

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
      }
    }
  }
}

对此建模的正确方法是为参与者提供两种状态,显式或隐式。这两者之间的选择取决于客户与该参与者的交互方式:

  • 参与者在没有可用令牌的情况下以否定方式回答请求,或者
  • 参与者在没有令牌的情况下存储请求,并在令牌可用时进行应答
显式模型使用
context.been()

隐式模型在Actor中存储一个
var-token:Option[AuthToken]
,从None开始


关于故障处理:你可以做你想做的任何事情,我建议停止执行者,让主管在给定时间后重新创建它,因为主管策略总是立即执行。

我会避免在构造函数中执行这些操作。使用两种状态(未授权和授权),然后通过
上下文切换接收方法。变成
在状态之间来回切换。非常感谢!这正是我想要的。你是否碰巧有一个链接指向更多显示常见akka模式的资源?我们在文档中描述了一些,但更多内容可以通过Google找到(这意味着这些信息分布在许多优秀的博客上)。杰米和我也在写作,但我们只是从书的这一部分开始。
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)
    ...
  }
}