使用 tell 构建 Rest API

Build Rest API using tell

我正在尝试找出使用 akka 和 akka-http 创建 REST API 的好方法。根据文档,request/reply 不是参与者间通信的最佳解决方案。所以我的问题是如何使用 tell 实现类似于此代码段的内容?

for {
    randomNumber <- (actor1 ? GetRandomNumber).mapTo[Int]
    randomString <- (actor2 ? GetRandomString).mapTo[String]
  } yield s"Random String: $randomString, Random Number: $randomNumber"

您可以封装一个状态来收集其他参与者的响应,并在完全提供时对其进行处理。

要在代码中解释这一点,请考虑以下示例

case class State(string: Option[String], int: Option[Int])

class CombiningActor(stringActor: ActorRef, intActor: ActorRef)
    extends Actor {

  override def receive: Receive = { case _ =>
    stringActor ! "Get Random String"
    intActor ! "Get Random Int"
    context.become(onMessage(State(string = None, int = None)))
  }

  private def onMessage(state: State): Receive = {
    case msg: String =>
      val newState = state.copy(string = Option(msg))
      whenSateFullyProvided(newState)
      context.become(onMessage(newState))
    case msg: Int =>
      val newState = state.copy(int = Option(msg))
      whenSateFullyProvided(newState)
      context.become(onMessage(newState))
  }

  private def whenSateFullyProvided(state: State): Unit = {
    if (state.string.nonEmpty && state.int.nonEmpty) {
      // Process the state here
    }
  }
}

状态积累是在 context.become 的帮助下发生的,

Changes the Actor's behavior to become the new 'Receive' (PartialFunction[Any, Unit]) handler. Replaces the current behavior on the top of the behavior stack.

请注意,如果您的 actor 应同时处理其他消息,则行为切换的处理会更加复杂。

如果您不想使用 context.becomeprivate var state: State 作为 CombiningActor 的变量字段也可以用来获得相同的结果。

最后一点,请不要对未类型化 actor 中的消息使用原始类型。很难理解代码,如果两个不同的参与者发送相同的原始类型可能会出现问题。