如何使用ask模式编译一系列结果

时间:2016-07-14 19:21:14

标签: scala akka

假设我有一个接收消息的worker actor,进行一些处理并返回结果。我有一系列消息需要转换成一系列结果:

object Test {

  case class Message(str: String)
  case class Result(str: String)

  class Worker extends Actor {
    def receive = {
        case Message(data) =>
            println("Sleeping: " + data)
            Thread.sleep(10000)
            val result = Result(data + " - result")
            println("Sending result: " + result)
            sender ! result
    }
  }

  def test(messages: Seq[Message]): Future[Seq[Result]] = {
    val worker = ActorSystem().actorOf(Props(new Worker))
    val results = messages.map { m =>
        implicit val timeout = Timeout(20 seconds)
        println("Sending: " + m)
        val result = worker ? m
        result.asInstanceOf[Future[Result]]
    }
    Future.sequence(results)
  }

  def main(args: Array[String]): Unit = {
    val messages: Seq[Message] = args.map(Message(_))
    test(messages).foreach { r =>
        println("Result: " + r)
    }
}

}

如果我只使用“message-1”作为参数运行上面的操作,它运行正常,输出如下:

  

发送:消息(消息-1)

     

睡觉:消息-1

     

发送结果:结果(消息-1 - 结果)

     

结果:ArraySeq(结果(消息-1 - 结果))

但是说我这样做:“message-1”“message-2”“message-3”然后最后一条消息最终被发送到deadLetters:

  

发送:消息(消息-1)发送:消息(消息-2)休眠:   message-1发送:消息(消息-3)

     

发送结果:结果(消息-1 - 结果)

     

睡觉:消息-2

     

发送结果:结果(消息-2 - 结果)

     

睡觉:消息-3

     

发送结果:结果(消息-3 - 结果)

     

[INFO] [07/15/2016 09:07:49.832]   [default-akka.actor.default-dispatcher-2] [akka:// default / deadLetters]   消息[util.Tester $ Result]来自   演员[akka://默认/用户/ $ a#1776546850]来   演员[akka:// default / deadLetters]未送达。 [1]死信   遇到。可以使用关闭或调整此日志记录   配置设置'akka.log-dead-letters'和   'akka.log止字母-期间关断'。

我猜这是因为我的调用线程在发送最后一条消息时超出了范围。如何正确地将所有结果收集到序列中?

请注意,将我的测试方法更改为以下结果会产生相同的结果:

def test(messages: Seq[Message]): Future[Seq[Result]] = {
    val worker = ActorSystem().actorOf(Props(new Worker))
    Future.traverse(messages) { m =>
        implicit val timeout = Timeout(20 seconds)
        println("Sending: " + m)
        val result = worker ? m
        result.asInstanceOf[Future[Result]]
    }
}

2 个答案:

答案 0 :(得分:0)

愚蠢的回答是:

Future.traverse(messages)(m => actor ? m).map(_.asInstanceOf[Result])

但最好一次发送数据:

class Worker extends Actor { 
  def receive = {
    case Message(data) =>
      // Convert data into result
      ...
      sender ! result
    case seq: Seq[Message] =>
      ...
      sender ! results

  }
}

答案 1 :(得分:0)

似乎是因为我的超时设置得太低了。应该足够大以涵盖所有工作 - 例如40秒。