scala - Future Recursion Patterns/Future Chaining of arbitrary length -



scala - Future Recursion Patterns/Future Chaining of arbitrary length -

i'm curious best way recursively build chain of akka futures run sequentially, if dowork phone call in future fails, future should retried 3 times, chain should fail if runs out of retry attempts. assuming dowork calls pass returned future futchain should complete.

object main extends app { val futchain = recurse(2) def recurse(param: int, retries: int = 3): future[string] { future { doworkthatmayfailreturningstring(param...) } recoverwith { case e => if (retries > 0) recurse(param, retries -1) else future.failed(e) } flatmap { strres => recurse(nextparam) //how should res previous fut passed? } } futchain oncomplete { case res => println(res) //should print strings } } how can results collection? i.e. in illustration each string homecoming dowork function (i need somehow modify recurse func homecoming futrue[list[string]] should utilize recover or recoverwith? is ok phone call flatmap chain these calls should create considerations tail recursion & stack overflows? would improve recursively build list of futures , cut down them?

you can implement retryable future this:

def retry[t](f: => future[t])(n: int)(implicit e: executioncontext): future[t] = { n match { case if (i > 1) => f.recoverwith{ case t: throwable => retry(f)(n - 1)} case _ => f } }

this isn't optimized tail recursion, if intend on retrying few times, won't stack overflow (and imagine if it's failed first few, it's going maintain failing, anyway).

then chaining separately. if have finite number of functions chain together, each depending on previous (and reason want aggregate results) can utilize for comprehensions (syntactic sugar flatmap):

for { firstresult <- retry(future(dowork(param)))(3) secondresult <- retry(future(dowork(firstresult)))(3) thirdresult <- retry(future(dowork(secondresult)))(3) } yield list(firstresult, secondresult, thirdresult)

for arbitrarily long chains, can them in parallel using future.sequence (futures in akka library):

def dowork(param: string): string = ... val parameters: list[string] = list(...) val results: future[list[string]] = future.sequence(parameters.map(dowork(_)))

this unravel otherwise list[future[string]] future[list[string]].

here's 1 way similar thing in sequence:

def sequential[a, b](seq: list[a])(f: => future[b])(implicit e: executioncontext): future[list[b]] = { seq.foldleft(future.successful(list[b]())) { case (left, next) => left.flatmap(list => f(next).map(_ :: list)) } } def dowork(param: string): string = ... val results: future[list[string]] = sequential(parameters)(param => future(dowork(param)))

the implementation of these functions very sensitive utilize case. 2 above functions homecoming failed futures if of futures in chain failed. you'll want this, other times not. if want collect successful futures, , discard failed ones without failing entire result, can add together step recover failures.

additionally, difference between recover , recoverwith type of partialfunction accepts. recover replaces failed futures default values, while recoverwith using future. in case of retry, recoverwith more appropriate because i'm trying recover failed future itself.

scala recursion akka future

Comments

Popular posts from this blog

php - Android app custom user registration and login with cookie using facebook sdk -

django - Access session in user model .save() -

php - .htaccess Multiple Rewrite Rules / Prioritizing -