Suppose we have a class which allocates some resources on the heap, and creating it takes some time, so it's hidden behind the future
class Container(val n: Int) {
allocateMemoryOnTheHeap(n)
def cleanup(): ???
}
def prepareContainer(val n: Int): Future[Container] = ???
Our task is to download a list of values and put it inside our container class. If any of the downloads failed we want to return a failure and release the resources.
def downloadNumber(): Future[Int] = ???
def numbersProvider(howMany: Int): Future[Seq[Int]] = (0 until howMany).map(downloadNumber).map(Future.sequence)
def prepareContainersForValuesFromUpstream(): Future[Seq[Container]] = {
val futureNumbers = numbersProvider(42)
val containersFuture: Future[Seq[Future[Container]]] = futureNumbers.map {
numbers =>
numbers.map(prepareContainer(_))
}
containersFuture.flatMap(Future.sequence)
}
def main() = {
val containersFuture = prepareContainersForValuesFromUpstream()
val result = Await.result(containersFuture, timeout)
result match {
case Success(_) => println("Downloaded values and stored in containers for later!")
case Failure(_) => //todo: how to release resources from created containers?
}
}
How can we do it? I think that applying Future.sequence
in the prepareContainersForValuesFromUpstream
makes it impossible, so we need to address this problem before it. But applying some tricks like this (Scala: List[Future] to Future[List] disregarding failed futures) makes it hard to convert the result to the proper form.