Akka Typed:回复来自不同参与者的消息(告诉)

vx6bjr1n  于 2023-10-18  发布在  其他
关注(0)|答案(1)|浏览(145)

使用Akka classic,可以轻松实现服务(作为参与者:ServiceActor),

  • 接收来自不同参与者的请求(即,不同类型的参与者:请求者A、请求者B等),
  • 处理该请求,
  • 向请求者发回确认。

请求者A向ServiceActor发送RequestMessage,ServiceActor向请求者A发回Acknowledgement
类似地,RequestorB向ServiceActor发送RequestMessage,ServiceActor向RequestorB发回Acknowledgement
无论请求是什么,都只有一种类型的RequestMessage和Acknowledgement,所有RequestMessage都由ServiceActor以相同的方式处理。
如何使用Akka Typed实现类似的功能?现在请求消息必须包含显式的replyTo:ActorRef[RequestorA.Message],有没有一种方法可以避免为每个请求者实现不同的RequestMessage?

  • RequestFromRequestorA(replyTo:ActorRef[请求者A.消息])
  • RequestFromRequestorB(replyTo:ActorRef[请求者B.消息])

类似地,有没有一种方法可以避免向每种类型的请求者发回不同类型的确认?

ftf50wuq

ftf50wuq1#

通常在Akka Typed中,响应消息由处理请求的Actor的协议定义,例如(在Scala中):

object MyActor {
  sealed trait Command

  case class Request(replyTo: ActorRef[Response]) extends Command

  sealed trait Response

  // and so forth
}

然后,发送Request的参与者有责任安排处理Response。如果发出请求的参与者只是为了发送请求而存在,它可以将自己定义为Behavior[Response],但在更一般的情况下,可以使用几种策略。
参与者可以设置消息适配器:

val responseRef = context.messageAdapter { response =>
  // convert to this actor's message protocol
  ???
}

otherActor ! MyActor.Request(responseRef)

如果这样做,通常最好只设置一次responseRef(例如,以Behaviors.setup为单位)。
如果参与者只执行一次请求,或者只期望每个请求有一个响应(并且期望在有限的时间内得到响应),那么“ask模式”可能更清晰:

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

这确实需要您定义一个显式的超时,并处理没有及时收到响应的情况。注入到Request消息中的ActorRef是短暂的:它将不会接收到发送给它的第一消息之外的任何消息,也不会接收到超时之后的消息。
还可以将参与者的行为定义为Behavior[Any](类似于“经典”无类型参与者),但不将该事实暴露在参与者之外。在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]

派生的ActorRef将是一个ActorRef[Command](即仅承诺处理Command),但参与者能够决定承诺处理它想要处理的任何消息(即使不是Command)。当这个参与者向它自己发送消息时,这确实会使你退出编译器的帮助;此外,这可能是一个有点模糊的模式,所以它的使用应该得到很好的注解。

相关问题