Wednesday 15 July 2015

Scala - Execute arbitrary number of Futures sequentially but dependently -



Scala - Execute arbitrary number of Futures sequentially but dependently -

this question has reply here:

is there sequential future.find? 3 answers

i'm trying figure out neatest way execute series of futures in sequence, 1 future's execution depends on previous. i'm trying arbitrary number of futures.

user case:

i have retrieved number of ids database. i need retrieve related info on web service. i want stop 1 time i've found valid result. i care result succeeded.

executing these in parallel , parsing collection of results returned isn't option. have 1 request @ time, , execute next request if previous request returned no results.

the current solution along these lines. using foldleft execute requests , evaluating next future if previous future meets condition.

def dblfuture(i: int) = { * 2 } val list = list(1,2,3,4,5) val future = list.foldleft(future(0)) { (previousfuture, next) => { { previousresult <- previousfuture nextfuture <- { if (previousresult <= 4) dblfuture(next) else previousfuture } } yield (nextfuture) } }

the big downside of a) maintain processing items 1 time i've got result i'm happy , b) 1 time i've found result i'm after, maintain evaluating predicate. in case it's simple if, in reality more complicated.

i sense i'm missing far more elegant solution this.

looking @ example, seems though previous result has no bearing on subsequent results, , instead matters previous result satisfies status prevent next result beingness computed. if case, here recursive solution using filter , recoverwith.

def untilfirstsuccess[a, b](f: => future[b])(condition: b => boolean)(list: list[a]): future[b] = { list match { case head :: tail => f(head).filter(condition).recoverwith { case _: throwable => untilfirstsuccess(f)(condition)(tail) } case nil => future.failed(new exception("all failed..")) } }

filter called when future has completed, , recoverwith called if future has failed.

def dblfuture(i: int): future[int] = future { println("executing.. " + i) * 2 } val list = list(1, 2, 3, 4, 5) scala> untilfirstsuccess(dblfuture)(_ > 6)(list) executing.. 1 executing.. 2 executing.. 3 executing.. 4 res1: scala.concurrent.future[int] = scala.concurrent.impl.promise$defaultpromise@514f4e98 scala> res1.value res2: option[scala.util.try[int]] = some(success(8))

scala future sequential for-comprehension foldleft

No comments:

Post a Comment