ここでの問題は、senia が指摘したように、不明な数のアクターに応答を求めることになるため、いつ応答を待っているかを知るのが非常に難しくなることです。応答を受け取る前に常にヒットする待機のタイムアウトを指定するのがクールな場合は、次のようなことができると思います。
//Message to send to the temp actor that handles request/response to the selection
case class AskSelection(path:String, msg:Any, askTimeout:FiniteDuration)
//Actor that handles the request to aggregate responses from a selection
class SelectionAsker extends Actor{
import context._
var responses:List[Any] = List.empty
def receive = waitingForRequest
def waitingForRequest:Receive = {
case request @ AskSelection(path, msg, askTO) =>
system.actorSelection(path) ! msg
setReceiveTimeout(askTO)
become(waitingForResponses(sender, askTO.fromNow))
}
def waitingForResponses(originator:ActorRef, deadline:Deadline):Receive = {
case ReceiveTimeout =>
originator ! responses
context.stop(self)
case any =>
responses = any :: responses
setReceiveTimeout(deadline.timeLeft)
}
}
//Factory to create the selection asker
object SelectionAsker{
def apply(fact:ActorRefFactory) = fact.actorOf(Props[SelectionAsker])
}
ここでの一般的な考え方は、別の短命で一時的なアクターを仲介役として使用して、選択からの応答を集約するというものです。前述のように、待機する応答の数がわからないため、送信者に応答する前に、指定された ask タイムアウトの全量を待機する必要があります。次のように使用できます。
val system = ActorSystem("test")
system.actorOf(Props[ActorA], "actor-a")
system.actorOf(Props[ActorB], "actor-b")
implicit val timeout = Timeout(2 seconds)
import system._
val asker = SelectionAsker(system)
(asker ? AskSelection("/user/actor*", "foo", 1 seconds)) onComplete { tr =>
println(tr)
}
class ActorA extends Actor{
def receive = {
case _ =>
sender ! "a"
}
}
class ActorB extends Actor{
def receive = {
case _ =>
sender ! "b"
}
}
きれいではありませんが、これが本当に必要な場合はうまくいく可能性があります。しかし、それが最初にやりたいことであり、ユースケースに追加する必要がある少し余分なコードであるため、最初により良い簡単なオプションがないことを確認する必要があります。