Skip to content

Instantly share code, notes, and snippets.

@davideicardi
Last active January 29, 2021 01:01
Show Gist options
  • Save davideicardi/41ec2a3762df7be9b699eb97eb2556d7 to your computer and use it in GitHub Desktop.
Save davideicardi/41ec2a3762df7be9b699eb97eb2556d7 to your computer and use it in GitHub Desktop.
Scala Future utilities to process elements asynchronous one after another
import scala.concurrent.{ExecutionContext, Future}
object FutureUtils {
/**
* Process elements asynchronous one after another.
* Equivalent to `Future.sequence(elements.map(transform))`
* but doing the processing sequentially instead of in parallel
*/
def mapAsyncSequentially[TInput, TResult](elements: Iterable[TInput])
(mapFunction: TInput => Future[TResult])
(implicit executionContext: ExecutionContext) : Future[Seq[TResult]] = {
val initial: Future[Seq[TResult]] = Future.successful(Seq())
elements
.foldLeft(initial) { (previousFuture, element) =>
previousFuture.flatMap { results =>
// when the previous Future is completed I run the next one
mapFunction(element).map(results :+ _)
}
}
}
}
import org.scalatest.funspec.AsyncFunSpec
import org.scalatest.matchers.should.Matchers
import scala.concurrent.Future
class FutureUtilsSpec extends AsyncFunSpec with Matchers {
describe("mapAsyncSequentially") {
it("should be equivalent to Future.sequence") {
val elements = Seq(1, 2, 3, 4, 5, 6, 7, 8, 9)
FutureUtils.mapAsyncSequentially(elements) { element =>
Future(element * 10)
}.map { results =>
results should be (elements.map(_ * 10))
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment