我正在开发一个 Finagle HTTP 应用程序,其中服务的实现没有利用 Futures 并通过第三方库访问 Redis。此类服务具有以下形式:
class SampleOldService extends Service[Request, Response] {
def apply(req: Request): Future[Response] = {
val value: Int = getValueFromRedis()
val response: Response = buildResponse(value)
Future.value(response)
}
}
(它们比这复杂得多——这里的重点是它们是同步的。)
在某个时候,我们开始使用 Futures 和 Finagle Redis API 开发新服务。Redis 调用封装在 Store 类中。新服务具有以下形式:
class SampleNewService extends Service[Request, Response] {
def apply(req: Request): Future[Response] = {
val value: Future[Int] = Store.getValue()
val response: Future[Response] = value map buildResponse
response
}
}
(它们比这复杂得多——这里的重点是它们是异步的。)
我们开始重构旧服务以利用异步性和 Futures。我们希望逐步地做到这一点,而不必一次完全重新实现它们。
第一步是尝试使用新的 Store 类,代码如下:
class SampleOldService extends Service[Request, Response] {
def apply(req: Request): Future[Response] = {
val valueFuture: Future[Int] = Store.getValue()
val value: Int = Await.result(valueFuture)
val response: Response = buildResponse(value)
Future.value(response)
}
}
然而,事实证明这是灾难性的,因为在重负载时,对旧服务的请求会停留在 Await.result() 调用中。新的异步服务显示没有问题。
该问题似乎与线程耗尽和/或未来池有关。我们已经找到了几个关于如何使用自定义池(例如FuturePool )从异步调用中进行同步调用(执行 I/O)的解决方案,但不是相反,这是我们的案例。
那么,在 Finagle 中从同步代码调用异步代码(执行 I/O)的推荐方式是什么?