Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execute Scala Futures in serial one after the other

Tags:

scala

future

Given a method that returns a Future like this...

def myMethod(name: String, count: Int, default: Boolean): Future[Unit] = {
  ...
}

... I need to invoke it N times, so I've defined a list of tuples containing the parameters to be passed:

val paramList = List(
  ("text1", 22, true),
  ("text2", 55, true),
  ("text3", 77, false)
)

How do I invoke myMethod with Future.traverse?

Future.traverse(paramList)(myMethod _).tupled(/* how do I pass the current tuple here? */)
like image 823
j3d Avatar asked Sep 16 '14 21:09

j3d


1 Answers

Two possible approaches:

val futuresFromSequence: Future[List[Unit]] = Future.sequence(paramList.map { 
  case (a,b,c) => myMethod(a,b,c) 
})

val futuresFromTraverse: Future[List[Unit]] = Future.traverse(paramList)(x => x match {
  case(a,b,c) => myMethod(a,b,c)
})

Note that traverse takes some collection and a function from an item of that collection to a future, sequence instead takes a list of futures and folds it to a future of list.

If you want to stick with the tupled syntax (which I personally dislike):

Future.traverse(paramList)(x => (myMethod _).tupled(x))

As noted in the comments you may want to run them in serial (although it's not 100% clear from the question), in that case you can use foldLeft and flatMap to chain future execution:

myList.foldLeft(Future(List.empty[Unit]))((prevFuture, currentTuple) => {
  for {
    prev <- prevFuture
    curr <- (myMethod _).tupled(currentTuple)
  } yield prev :+ curr
})

Where basically the first generator waits for the future in the accumulator to complete before launching the new one, this also returns a Future[List[Unit]].

like image 79
Ende Neu Avatar answered Sep 28 '22 04:09

Ende Neu