Akka Stream油门和问模式

时间:2017-07-31 15:12:25

标签: scala akka akka-stream

我之前使用过akka.contrib的TimerBasedThrottler,但现在已被弃用并替换为akka stream throttle。这是我的演员

class MyActor extends Actor{

    def receive = {
        case Message(msg) =>
        val date = LocalDateTime.now()
        println(s"getting: $msg @ $date from ${sender()}")
        sender() ! s"$msg ack"
    }
}

这是我的节流器

val throttler = Source.actorRef(bufferSize = 1000, OverflowStrategy.dropNew)
                      .throttle(1, 1.second, 1, ThrottleMode.shaping)
                      .to(Sink.actorRef(myActor, NotUsed))
                      .run()

我这样使用它:

val res = (throttler ? MyActor.Message("hello")).mapTo[String]

但我收到错误:

akka.pattern.AskTimeoutException: Ask timed out on [Actor[akka://QuickStart/user/StreamSupervisor-0/flow-0-2 actorRefSource#355339300]] after [2000 ms]. Sender[null] sent message of type "MyActor$Message".

1 个答案:

答案 0 :(得分:0)

这不起作用,因为throttler是与MyActor不同的角色,因此它不会向发件人发回任何内容。虽然您自己的myActor确实回复了发件人,但内部传入的邮件是由akka-streams内部发送的,它会忽略任何回复。毕竟,流中的消息总是以单一方向流动(另一个方向是为需求保留的)。

您可以做的是将引用传递给原始actor,并带有以下消息:

class Sender(myActor: ActorRef)
            (implicit materializer: Materializer) extends Actor {
  val throttler = Source.actorRef[(MyActor.Message, ActorRef)](bufferSize = 1000, OverflowStrategy.dropNew)
    .throttle(1, 1.second, 1, ThrottleMode.shaping)
    .to(Sink.actorRef(myActor, NotUsed))
    .run()

  override def receive: Receive = {
    case DoIt =>
      throttler ! (MyActor.Message("hello"), self)
    case response: String =>
      println(s"received response: $response")
  }
}

class MyActor extends Actor {
  override def receive: Receive = {
    case (MyActor.Message(msg), originalSender: ActorRef) =>
      val date = LocalDateTime.now()
      println(s"getting: $msg @ $date from $originalSender")
      originalSender ! s"$msg ack"
  }
}

object MyActor {
  case class Message(msg: String)
}

当然,为了扩展,最好将原始发送者合并到消息类中,但基本方法保持不变。