简体   繁体   English

Akka:将错误从路由发回给呼叫者

[英]Akka: send error from routee back to caller

In my project, I created UserRepositoryActor which create their own router with 10 UserRepositoryWorkerActor instances as routee, see hierarchy below: 在我的项目中,我创建了UserRepositoryActor ,它使用10个UserRepositoryWorkerActor实例作为路由创建了自己的路由器,请参见下面的层次结构: 演员阶层

As you see, if any error occur while fetching data from database, it will occur at worker. 如您所见,如果从数据库中获取数据时发生任何错误,它将在工作程序中发生。

Once I want to fetch user from database, I send message to UserRepositoryActor with this command: 一旦我想从数据库中获取用户,就UserRepositoryActor使用以下命令将消息发送到UserRepositoryActor

val resultFuture = userRepository ? FindUserById(1)

and I set 10 seconds for timeout. 我将超时设置为10秒。

In case of network connection has problem, UserRepositoryWorkerActor immediately get ConnectionException from underlying database driver and then (what I think) router will restart current worker and send FindUserById(1) command to other worker that available and resultFuture will get AskTimeoutException after 10 seconds passed. 在网络连接出现问题的情况下, UserRepositoryWorkerActor立即从底层数据库驱动程序获取ConnectionException ,然后(我认为)路由器将重新启动当前工作程序,并将FindUserById(1)命令发送给其他可用的工作程序,并且经过10秒后resultFuture将获得AskTimeoutException Then some time later, once connection back to normal, UserRepositoryWorkerActor successfully fetch data from database and then try to send result back to the caller and found that resultFuture was timed out. 然后过了一段时间,一旦连接恢复正常, UserRepositoryWorkerActor成功地从数据库中获取数据,然后尝试将结果发送回调用方,发现resultFuture超时。

I want to propagate error from UserRepositoryWorkerActor up to the caller immediately after exception occur, so that will prevent resultFuture to wait for 10 seconds and stop UserRepositoryWorkerActor to try to fetch data again and again. 我想在异常发生后立即将错误从UserRepositoryWorkerActor传播到调用者,这样可以防止resultFuture等待10秒并阻止UserRepositoryWorkerActor尝试一次又一次地获取数据。

How can I do that? 我怎样才能做到这一点?

By the way, if you have any suggestions to my current design, please suggest me. 顺便说一句,如果您对我目前的设计有任何建议,请提出建议。 I'm very new to Akka. 我是Akka的新手。

Your assumption about Router resending the message is wrong. 您对路由器重新发送消息的假设是错误的。 Router has already passed the message to routee and it doesnt have it any more. 路由器已经将该消息传递给路由,并且不再具有该消息。

As far as ConnectionException is concerned, you could wrap in a scala.util.Try and send response to sender() . ConnectionException而言,您可以包装scala.util.Try并将响应发送到sender() Something like, 就像是,

Try(SomeDAO.getSomeObjectById(id)) match {
    case Success(s) => sender() ! s
    case Failure(e) => sender() ! e
  }

You design looks correct. 您的设计看起来正确。 Having a router allows you to distribute work and also to limit number of concurrent workers accessing the database. 拥有路由器可以使您分配工作,还可以限制访问数据库的并发工作人员的数量。

Option 1 选项1

You can make your router watch its children and act accordingly when they are terminated. 您可以让路由器监视其子节点,并在终止它们时采取相应的措施。 For example (taken from here ): 例如(从此处获取 ):

import akka.routing.{ ActorRefRoutee, RoundRobinRoutingLogic, Router }

class Master extends Actor {
  var router = {
    val routees = Vector.fill(5) {
      val r = context.actorOf(Props[Worker])
      context watch r
      ActorRefRoutee(r)
    }
    Router(RoundRobinRoutingLogic(), routees)
  }

  def receive = {
    case w: Work =>
      router.route(w, sender())
    case Terminated(a) =>
      router = router.removeRoutee(a)
      val r = context.actorOf(Props[Worker])
      context watch r
      router = router.addRoutee(r)
  }
}

In your case you can send some sort of a failed message from the repository actor to the client. 在您的情况下,您可以从存储库参与者向客户端发送某种失败的消息。 Repository actor can maintain a map of worker ref to request id to know which request failed when worker terminates. Repository actor可以维护一个worker ref的映射来请求ID,以知道当worker终止时哪个请求失败。 It can also record the time between the start of the request and actor termination to decide whether it's worth retrying it with another worker. 它还可以记录从请求开始到参与者终止之间的时间,以决定是否值得与其他工作人员重试。

Option 2 选项2

Simply catch all non-fatal exceptions in your worker actor and reply with appropriate success/failed messages. 只需在工作人员中捕获所有非致命异常,并以适当的成功/失败消息进行回复。 This is much simpler but you might still want to restart the worker to make sure it's in a good state. 这要简单得多,但是您可能仍要重新启动工作程序,以确保它处于良好状态。

ps Router will not restart failed workers, neither it will try to resend messages to them by default. ps路由器不会重新启动失败的工作程序,默认情况下也不会尝试向其重新发送消息。 You can take a look at supervisor strategy and Option 1 above on how to achieve that. 您可以查看主管策略和上面的选项1,了解如何实现这一目标。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM