Reputation: 31
Hi I am trying to process data in a file.
This the code I am using below.
I have a list of Futures and trying to get the output from these futures.
Everything is fine but the last line of return is executing before OnSuccess.
How can I change that behaviour without having a blocking operation.
def processRow(rowNumber: Int, row: String, delimiter: String, rules: List[Rule]): RowMessage = {
var cells = row.split(delimiter)
var passedRules = new ListBuffer[RuleResult]()
val failedRules = new ListBuffer[RuleResult]()
val rulesFuture = rules.map {
i => Future {
val cells = row.split(delimiter);
//some processing....
}
}
val f1 = Future.sequence(rulesFuture)
f1 onComplete {
case Success(results) => for (result <- results) (result.map(x => {
if (x.isPassFailed) {
passedRules += x
}
else {
failedRules += x
}
}))
case Failure(t) => println("An error has occured: " + t.getMessage)
}
return new RowMessage(passedRules.toList, failedRules.toList)
}
Upvotes: 0
Views: 133
Reputation: 8663
You can't avoid blocking and return a plain RowMessage
. You need to return a Future
as well.
def processRow(rowNumber: Int, row: String, delimiter: String, rules: List[Rule]): Future[RowMessage] = {
val cells = row.split(delimiter)
Future.traverse(rules) { i =>
Future {
//some processing....
}
} map { results =>
val (passed, failed) = results.partition(_.isPassFailed)
new RowMessage(passed, failed)
}
}
Also think about your algorithm to avoid mutable state, especially when you change it from different Futures.
Future.traverse
is equivalent of your map
+ Future.sequence
. Then instead of onComplete, just map your Future
to modify the list. You can split it easly using partition
instead of what you've been doing.
You don't need to use return
, in fact you shouldn't unless you know what you are doing.
Btw isPassFailed
doesn't sound like a reasonable method name to me, especially considering that when it's true you are adding it to passed rules.
Upvotes: 1