dav*_*vid 0 scala akka akka-typed
使用 Akka classic,人们可以轻松实现一项服务(作为参与者:ServiceActor)
RequestorA 向 ServiceActor 发送 RequestMessage ServiceActor 向 RequestorA 发回 Acknowledgment
类似地,RequestorB 向 ServiceActor 发送 RequestMessage,ServiceActor 向 RequestorB 发回 Acknowledgment
无论Requestor是什么,都只有一种类型的RequestMessage和Acknowledgment,并且所有RequestMessage都由ServiceActor以相同的方式处理。
使用 Akka Typed 实现类似功能的方法是什么?既然请求消息必须包含显式的replyTo:ActorRef[RequestorA.Message],是否有办法避免为每个请求者实现不同的RequestMessage?
同样,是否有办法避免向每种类型的请求者发回不同类型的确认?
通常在 Akka Typed 中,响应消息由处理请求的 actor 的协议定义,例如(在 Scala 中):
object MyActor {
sealed trait Command
case class Request(replyTo: ActorRef[Response]) extends Command
sealed trait Response
// and so forth
}
Run Code Online (Sandbox Code Playgroud)
然后,发送 的参与者就有责任Request安排处理Response。如果请求参与者恰好只是为了发送请求而存在,它可以将自己定义为Behavior[Response],但在更一般的情况下,可以使用几种策略。
参与者可以设置消息适配器:
val responseRef = context.messageAdapter { response =>
// convert to this actor's message protocol
???
}
otherActor ! MyActor.Request(responseRef)
Run Code Online (Sandbox Code Playgroud)
如果这样做,通常最好设置responseRef唯一一次(例如在 中Behaviors.setup)。
如果参与者只想执行一次请求,或者只期望每个请求得到一个响应(并且期望在有限的时间内得到该响应),那么“询问模式”可能会更清晰:
implicit val timeout: Timeout = 15.seconds
context.ask(otherActor, MyActor.Request(_)) {
case Success(resp) =>
// convert to this actor's message protocol
???
case Failure(ex) =>
// convert to this actor's message protocol
???
Run Code Online (Sandbox Code Playgroud)
这确实需要您定义显式超时并处理未及时收到响应的情况。注入ActorRef的Request消息是短暂的:除了发送给它的第一条消息之外,它不会接收任何消息,也不会在超时后接收消息。
也可以将 actor 的行为定义为 a Behavior[Any](这就像“经典”的无类型 actor),但不将该事实暴露在 actor 之外。在 Scala 中,由于逆变,这相当简单且安全:
Behaviors.setup[Any] { context =>
// context.self is an ActorRef[Any], which by contravariance is usable as any type of ActorRef
otherActor ! MyActor.Request(context.self)
Behaviors.receiveMessage {
case resp: MyActor.Response =>
// handle response directly
???
case _ =>
Behaviors.unhandled
}
}.narrow[Command]
Run Code Online (Sandbox Code Playgroud)
生成的ActorRef将是 an ActorRef[Command](即仅承诺处理Command),但参与者能够决定承诺处理它想要处理的任何消息(即使不是 a Command)。当涉及到该参与者向自身发送消息时,这确实会使您脱离编译器的帮助;此外,这可能是一个有点晦涩的模式,因此它的使用应该得到很好的评论。