Reputation: 989
I have two source of data which returns List[Int]
// first work with postgresql database
object Db {
def get: Future[List[Int]] = // impl
}
// second it's remote service
object Rs {
def get: Future[List[Int]] = // impl
}
And then i want to return two lists. But i do not know how to dealing with exceptions:
Db possible throw ConnectionUnavailable
Remote service - Bad Request, or InternalServer error
Both - TimeoutException
But, when i have only results from db, i want to return it. If i have results from db and from remote service i want to return sum of two lists.
How to work with this case?
Upvotes: 1
Views: 489
Reputation: 127781
You need to combine flatMap
and recover
:
for {
db <- Db.get
rs <- Rs.get.recover {
case e =>
logger.error("Error requesting external service", e)
List.fill(db.length)(0)
}
} yield (db, rs).zipped.map(_+_).sum
You can tweak the transformations if you like (I assumed that you meant element-wise sum of lists), but the basic idea stays the same - if you want to "ignore" the failure of some future, you need to call recover
on it.
If you want, you can extract the recovering function from the for
comprehension, but recover
still has to be called inside of it:
def handler(n: Int): PartialFunction[Throwable, List[Int]] = {
case e =>
logger.error("Error requesting external service", e)
List.fill(n)(0)
}
for {
db <- Db.get
rs <- Rs.get.recover(handler(db.length))
} yield (db, rs).zipped.map(_+_).sum
Upvotes: 2
Reputation: 108101
val total: Future[Int] =
Db.get.flatMap { dbResults =>
Rs.get.map { remoteResults =>
dbResults.sum + remoteResults.sum
}
}
or equivalently
val total: Future[Int] = for {
dbResults <- Db.get
remoteResults <- Rs.get
} yield dbResults.sum + remoteResults.sum
I explicitly annotated the result type for the sake of clarity but it's not necessary.
total
is a Future[Int]
holding either a successful or a failed computation. If you need to handle errors you can attach a onFailure
handler on it. For instance
total.onFailure {
case e: TimeoutException => // ...
case e: ConnectionError => // ...
}
(the names of the exceptions are made up)
Upvotes: 5