假设我有一个接收消息的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]]
}
}
答案 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秒。