Scala 在单个超时时处理未知数量的参与者结果
我希望扩展以下代码以处理未知数量的actor ask请求Scala 在单个超时时处理未知数量的参与者结果,scala,akka,actor,Scala,Akka,Actor,我希望扩展以下代码以处理未知数量的actor ask请求 implicit val timeout = Timeout(100 millis) val sendRequestActor = context.actorOf(Props(new SendRequest(request)), "Send_Request_".concat(getActorNumber)) val sendRequestActor2 = context.actorOf(Props(new SendRequest(requ
implicit val timeout = Timeout(100 millis)
val sendRequestActor = context.actorOf(Props(new SendRequest(request)), "Send_Request_".concat(getActorNumber))
val sendRequestActor2 = context.actorOf(Props(new SendRequest(request)), "Send_Request_".concat(getActorNumber))
val a1 = ask(sendRequestActor, Request).fallbackTo(Future.successful(RequestTimeout))
val a2 = ask(sendRequestActor2, Request).fallbackTo(Future.successful(RequestTimeout))
val result = for {
r1 <- a1
r2 <- a2
} yield(r1, r2)
val r = Await.result(result, 100 millis)
r match {
case (b: SuccessResponse, b2: SuccessResponse) => {
//Process Results
}
case (b: SuccessResponse, b2: RequestTimeout) => {
//Process Results
}
case (b: RequestTimeout, b2: SuccessResponse) => {
//Process Results
}
case (b: RequestTimeout, b2: RequestTimeout) => {
//Process Results
}
case _ => {}
}
已更新的发送类:
case object GetResponses
def main(args: Array[String]) {
val route = {
get {
complete {
//stuff
val req_list = List(req1,req2,req3)
val createRequestActor = system.actorOf(Props(new SendAll(req_list)), "Get_Response_Actor_" + getActorNumber)
val request_future = ask(createRequestActor, GetResponses).mapTo[List[Any]]
Thread.sleep(1000)
println(request_future)
//more stuff
}
}
}
Http().bindAndHandle(route, "localhost", 8080)
}
class SendAll(requests: List[Request]) extends Actor {
import context.{become,dispatcher}
var numProcessed = 0
var results: List[Any] = List()
requests.foreach(self ! _)
implicit val timeout = Timeout(100 millis)
def receive = {
case r: RequestMsg =>
val sendRequestActor = context.actorOf(Props(new SendRequest(r)), "Send_Request_".concat(getActorNumber))
(sendRequestActor ? Request).pipeTo(self)
case s: SuccessResponse =>
println("Got Success")
results = results :+ s
println(results.size + " == " + requests.size)
if(results.size == requests.size) {
println("Before done")
become(done)
}
case akka.actor.Status.Failure(f) =>
println("Got Failed")
results = results :+ RequestTimeout
if(results.size == requests.size) {
become(done)
}
case m =>
println("Got Other")
}
def done: Receive = {
case GetResponses =>
println("Done")
sender ! results
case _ => {
println("Done as well")
}
}
}
输出
Got Success
1 == 3
Got Success
2 == 3
Got Success
3 == 3
Before done
Future(<not completed>)
我会将请求列表传递给参与者,然后将子参与者的响应传递给self,而不是使用wait.result。例如:
class Handler(requests: List[RequestMsg]) extends Actor {
import context.{become, dispatcher}
var numProcessed = 0
var results: List[Any] = List()
requests.foreach(self ! _)
implicit val timeout = Timeout(100.millis)
def receive = {
case r: RequestMsg =>
val sendRequestActor = context.actorOf(Props(new SendRequest(r)), "Send_Request".concat(getActorNumber))
(sendRequestActor ? Request).pipeTo(self)
case s: SuccessResponse =>
println(s"response: $s")
results = results :+ s
if (results.size == requests.size)
become(done)
case akka.actor.Status.Failure(f) =>
println("a request failed or timed out")
results = results :+ RequestTimeout
if (results.size == requests.size)
become(done)
case m =>
println(s"Unhandled message received while processing requests: $m")
sender ! NotDone
}
def done: Receive = {
case GetResponses =>
println("sending responses")
sender ! results
}
}
您将为每个请求列表实例化一个参与者:
val requests1 = List(RequestMsg("one"), RequestMsg("two"), RequestMsg("three"))
val handler1 = system.actorOf(Props(new Handler(requests1)))
在本例中,根据参与者应具有明确、有限责任范围的原则,参与者只需协调请求和响应;它不会对收集的响应执行任何处理。其想法是,另一个参与者将向该参与者发送GetResponses消息,以获取响应并对其进行处理,或者该参与者将主动将结果发送给处理参与者。最简单的解决方案是将所有参与者引用放入列表,将其映射到列表[未来],并用于获取未来[列表]
一个更好的解决方案是避免很多参与者的请求,准备一些响应Collector actor,它将发送您的所有消息。我建议您查看广播池并为自己安排一条消息,以停止等待并返回结果。这看起来会满足我的要求。但是我对done函数有一个问题,它似乎根本没有被调用,也不一定是睡眠计时器。我以前让另一个参与者调用这个函数,并且将在这里进行处理。我更新了OP以包括我的呼叫类和我更新的发送类。有什么线索可以解释为什么我从来没有在我的“完成”类中看到任何打印内容以及我的未来没有完成?@Eumcoz:关于您的更新,有几点需要注意:1您的RequestHandler看起来很奇怪,因为它扩展了Actor并调用system.actorOf system.actorOf应该在主程序中调用,而不是从Actor内部调用。2您可能没有分配足够的时间来完成请求-响应处理。增加Thread.sleep或在将来使用onComplete回调。抱歉,我的错误,出于某种原因,我认为这是从其他地方调用的,在我的实际程序中,RequestHandler是我的主程序,是akka http处理程序。正在从http请求的指令调用SendAll。无论我睡眠多长时间,它都会失败,我的SendAll调用超时将生效:Failureakka.pattern.AskTimeoutException:Ask在[Actor]上超时[akka://HTTP_Actor_System/user/Get_Response_Actor_1-720534280]]在[10000毫秒]之后。发件人[null]已发送GetResponses$类型的邮件。在之前的测试中,我的响应处理大约需要5毫秒。
val route = {
get {
val listActorRefs = List(actorRef1, actorRef2, ...)
val futureListResponses = Future.sequence(listActorRefs.map(_ ? Request))
onComplete(futureListResponses) {
case Success(listResponse) => ...
complete(...)
case Failure(exception) => ...
}
}
}