【发布时间】:2015-03-29 16:55:25
【问题描述】:
我是 Scala 的 Future 新手,但我还没有找到解决问题的方法。我正在尝试实现以下目标(总体描述:尝试获取酒店列表的客人列表,分别查询每个酒店):
- 对另一个 API 进行 n 次调用,每次调用都有超时时间
- 合并所有结果(将列表列表转换为 包含所有元素)
- 如果单个调用失败,记录错误并返回一个空列表(基本上在这种情况下,如果我得到部分结果而不是完全没有结果会更好)
- 理想情况下,如果单个调用失败,在等待一段时间后重试 x 次,最终失败并处理错误,就像没有重试一样
这是我的代码。 HotelReservation 代表我要调用的外部 API。
import com.typesafe.scalalogging.slf4j.Logging
import scala.concurrent._, ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
case class Guest(name: String, country: String)
trait HotelReservation extends Logging {
def getGuests(id: Int): Future[List[Guest]] = Future {
logger.debug(s"getting guests for id $id")
id match {
case 1 => List(new Guest("John", "canada"))
case 2 => List(new Guest("Harry", "uk"), new Guest("Peter", "canada"))
case 3 => {
Thread.sleep(4000)
List(new Guest("Harry", "austriala"))
}
case _ => throw new IllegalArgumentException("unknown hotel id")
}
}
}
object HotelReservationImpl extends HotelReservation
HotelSystem 拨打电话。
import com.typesafe.scalalogging.slf4j.Logging
import scala.util.control.NonFatal
import scala.util.{Failure, Success}
import scala.concurrent._, duration._, ExecutionContext.Implicits.global
class HotelSystem(hres: HotelReservation) {
def pollGuests(hotelIds: List[Int]): Future[List[Guest]] = {
Future.sequence(
hotelIds.map { id => future {
try {
Await.result(hres.getGuests(id), 3 seconds)
} catch {
case _: Exception =>
Console.println(s"failed for id $id")
List.empty[Guest]
}
}
}
).map(_.fold(List())(_ ++ _)) /*recover { case NonFatal(e) =>
Console.println(s"failed:", e)
List.empty[Guest]
}*/
}
}
还有测试。
object HotelSystemTest extends App {
Console.println("*** hotel test start ***")
val hres = HotelReservationImpl
val hotel = new HotelSystem(hres)
val result = hotel.pollGuests(List(1, 2, 3, 6))
result onSuccess {
case r => Console.println(s"success: $r")
}
val timeout = 5000
Console.println(s"waiting for $timeout ms")
Thread.sleep(timeout)
Console.println("*** test end ***")
}
1 和 2 正在工作。 3 也是如此,但我想我在 SO 上的某个地方读到,在调用未来时尝试捕获不是一个好主意,最好使用恢复。但是,在这种情况下,如果我使用恢复,如果有单个失败,则整个调用都会失败并返回一个空列表。关于如何改进这一点的任何想法?
【问题讨论】:
标签: scala concurrency