简体   繁体   English

Scala与多个期货合作

[英]Scala work with multiple futures

I have two source of data which returns List[Int] 我有两个返回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: 但是我不知道如何处理异常:

  1. Db possible throw ConnectionUnavailable db可能抛出连接不可用

  2. Remote service - Bad Request, or InternalServer error 远程服务-错误的请求或InternalServer错误

  3. Both - TimeoutException 两者-TimeoutException

But, when i have only results from db, i want to return it. 但是,当我只有db的结果时,我想返回它。 If i have results from db and from remote service i want to return sum of two lists. 如果我有数据库和远程服务的结果,我想返回两个列表的和。

How to work with this case? 如何处理这种情况?

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. total是一个Future[Int]其中包含成功或失败的计算。 If you need to handle errors you can attach a onFailure handler on it. 如果需要处理错误,可以在其上附加onFailure处理程序。 For instance 例如

total.onFailure {
  case e: TimeoutException => // ...
  case e: ConnectionError  => // ...
}

(the names of the exceptions are made up) (组成例外的名称)

You need to combine flatMap and recover : 您需要结合flatMaprecover

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. 您可以根据需要调整转换(我假设您的意思是列表的元素加和),但是基本思想保持不变-如果您要“忽略”某些将来的失败,则需要对其进行调用recover

If you want, you can extract the recovering function from the for comprehension, but recover still has to be called inside of it: 如果需要,您可以从中提取恢复函数以for理解,但是仍然必须在其中调用recover

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM