I'm creating three actor tasks using future, and then trying to collect all three when finished. The current code is the following:
implicit val timeout = Timeout(5.seconds)
val result1 = actor1 ? DataForActor(data)
val result2 = actor2 ? DataForActor(data)
val result3 = actor3 ? DataForActor(data)
val answer = for {
a <- result1.mapTo[List[ResultData]]
b <- result2.mapTo[List[ResultData]]
c <- result3.mapTo[List[ResultData]]
} yield (a ++ b ++ c).sorted
answer onComplete {
case Success(resultData) =>
log.debug("All actors completed succesffully")
successActor ! SuccessData(resultData.take(2))
case Failure(resultData) =>
log.info("actors failed")
}
Each of the actors (actor1, actor2, actor3) manipulates the data and returns either None or Option(List(resultData)), as shown in the following code:
val resultData = if(data.size == 0) None else {
data.map {
...
try {
... //manipulation on resultData
Option(resultData)
}
catch {
case e: Exception => None
}
}.flatten
}
The for statement concatenates lists from each actor, and produces a long List(resultData).
I want that in the case that one actor returns None, it's result in the for statement will not add anything to the concatenation, i.e. List().
An example:
If I get: result1 = List(1, 2, 3), result2 = None, result3 = List(4, 5),
I want: resultData = List(1, 2, 3, 4, 5)
You could replace
None
withNil
beforemapTo
this way:Note that you should avoid
mapTo
with generic type likeList
:Because of type erasure
mapTo
can't prove that you have list ofInt
, notList
of some other type. You'll get the same problem withcase l: List[Int]
inreceive
method of actor.You should create special class for your messages like this: