[英]Play WS API: throttling request rates
我正在使用异步Play WS Scala API来查询RESTful服务。 我想知道如何处理包含要通过WSClient
调用的请求URL的List
,但每秒不超过一个请求(该服务允许每个客户端每秒“仅”1个请求)。 从逻辑的角度来看,我们的想法是从列表中获取元素(URL),发出请求,然后等待一段时间再继续列表中的下一个元素。
Thread.sleep
肯定是一个坏主意。 ScheduledThreadPoolExecutor
或其他需要生成新线程的方法,情况也是如此。 如何在不对Play的异步和“尽可能线程”性质产生负面影响的情况下限制请求率?
假设您有一个您要获取的URL列表:
val urls = List(
"http://www.google.com",
"http://stackoverflow.com",
"http://www.bing.com"
)
在Play 2.5.x中,我们可以按顺序处理它们,并使用akka.pattern.after
强制每次调用之间的异步延迟。 我们将Web服务调用的Future
结果flatMap
到一秒钟后将返回相同值的内容。
Future.traverse(urls) { url =>
wsClient.url(url).get().flatMap { result =>
// potentially process `result` here
akka.pattern.after(1.second, actorSystem.scheduler)(Future.successful(result))
}
} // returns Future[List[WSResponse]]
这要求您具有可用的WSClient
和ActorSystem
组件,以及范围中的隐式ExecutionContext
。
在Play 2.4.x及更早版本中,您可以使用Promise.timeout
执行相同的操作:
Future.traverse(urls) { url =>
wsClient.url(url).get().flatMap { result =>
// potentially process `result` here
Promise.timeout(result, 1.second)
akka.pattern.after(1.second, actorSystem.scheduler)(Future.successful(result))
}
}
Akka在这里有一个方便的调度程序功能: http : //doc.akka.io/docs/akka/current/scala/scheduler.html
由于Akka已经在Play中,因此您无需导入任何其他内容。
它不会是最干净或容易测试的,但你可以这样:
val webserviceCall : Runnable = new Runnable {
override def run(): Unit = {
// do webservice call work
// figure out if you need to make more webservice calls, and if you do:
actorSystem.scheduler.scheduleOnce(0 seconds, 1 seconds, webserviceCall)
}
}
actorSystem.scheduler.scheduleOnce(0 seconds, webserviceCall)
或者,您可以使用此人之前做过的这个Akka消息调节器: http : //doc.akka.io/docs/akka/snapshot/contrib/throttle.html
我之前使用过它(我认为去年是Akka 2.3)但不确定它是否仍然有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.