Akka:将来自routee的错误发送回来电者

时间:2015-11-17 07:47:29

标签: scala akka

在我的项目中,我创建了UserRepositoryActor,它创建了自己的路由器,其中10个UserRepositoryWorkerActor个实例作为routee,请参阅下面的层次结构: ActorHierarchy

如您所见,如果从数据库获取数据时发生任何错误,则会在worker处发生。

一旦我想从数据库中获取用户,我就会使用以下命令向UserRepositoryActor发送消息:

val resultFuture = userRepository ? FindUserById(1)

我设置10秒超时。

如果网络连接出现问题,UserRepositoryWorkerActor立即从底层数据库驱动程序获取ConnectionException,然后(我认为)路由器将重新启动当前工作程序并发送{{ 1}}命令给其他可用的工作者,FindUserById(1)将在10秒后获得resultFuture。然后一段时间后,一旦连接恢复正常,AskTimeoutException成功从数据库中获取数据,然后尝试将结果发送回调用者,发现UserRepositoryWorkerActor已超时。

我想在发生异常后立即将错误从resultFuture传播到调用方,这样可以防止UserRepositoryWorkerActor等待10秒并阻止resultFuture再次尝试获取数据然后再次。

我该怎么做?

顺便说一句,如果您对我目前的设计有任何建议,请建议我。我对Akka很新。

2 个答案:

答案 0 :(得分:0)

您对路由器重新发送邮件的假设是错误的。路由器已经将消息传递给了routee,它不再拥有它。

ConnectionException而言,您可以打包scala.util.Try并将回复发送给sender()。像,

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

答案 1 :(得分:0)

你的设计看起来很正确。拥有路由器可以分配工作,也可以限制访问数据库的并发工作者数量。

选项1

您可以让路由器监视其子女并在终止时采取相应行动。例如(取自here):

utkbansal@Dell:~$ which go
/usr/lib/go/bin/go

utkbansal@Dell:~$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/utkbansal/go"
GORACE=""
GOROOT="/usr/lib/go"
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GO15VENDOREXPERIMENT=""
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0"
CXX="g++"
CGO_ENABLED="1"


utkbansal@Dell:~$ $PATH
bash: /usr/lib/go/bin:/home/utkbansal/miniconda/bin:/usr/local/heroku/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/go/bin: No such file or directory

在您的情况下,您可以从存储库actor向客户端发送某种失败的消息。存储库actor可以维护worker ref的映射以请求id以知道当worker终止时哪个请求失败。它还可以记录请求开始和演员终止之间的时间,以决定是否值得与另一名工作人员重试。

选项2

只需捕获工作者中的所有非致命异常,并使用适当的成功/失败消息进行回复。这样做要简单得多,但您可能仍希望重新启动工作人员以确保其处于良好状态。

P.S。路由器不会重启失败的工作程序,也不会尝试默认重新发送消息。您可以查看主管策略和上面的选项1,了解如何实现这一目标。