2016-05-16 154 views
2

我正在使用異步播放WS Scala API來查詢REST式服務。我想知道如何處理List,其中包含通過WSClient調用的請求URL,但每秒請求數不超過一個(該服務允許「每個客戶端每秒只有」1個請求)。從邏輯的角度來看,這個想法是從列表中獲取一個元素(URL),發出請求,然後等待一定的時間,然後再繼續處理列表中的下一個元素。播放WS API:限制請求速率

  • 在像Play這樣的非阻塞和異步框架中使用舊的Thread.sleep肯定是一個壞主意。
  • 對於像ScheduledThreadPoolExecutor或其他需要產生新線程的方法,情況可能也是如此。

我該如何限制請求速率,而不會對Play的異步和「儘可能小的線程」性質產生負面影響?

+0

玩什麼版本的? –

+0

玩版本2.5.3 – ceran

回答

3

假設你有你看獲取的URL列表:

val urls = List(
    "http://www.google.com", 
    "http://stackoverflow.com", 
    "http://www.bing.com" 
) 

在玩2.5.X,我們可以處理這些順序,並使用akka.pattern.after迫使每個調用之間的異步延遲。我們flatMapFuture Web服務調用的結果將返回相同的值後一秒。

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]] 

這需要你有一個WSClientActorSystem組件可用,以及在隱ExecutionContext範圍。


在玩的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)) 
    } 
} 
1

阿卡在這裏有一個方便的調度功能:http://doc.akka.io/docs/akka/current/scala/scheduler.html

由於阿卡已經在玩,你不需要輸入任何東西。
這不會是最乾淨的或容易測試,但你可以是這樣的:

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) 

或者,您也可以使用這個阿卡消息節流,有人做了一個前一陣子:http://doc.akka.io/docs/akka/snapshot/contrib/throttle.html

我已經用它之前(我認爲這是去年的Akka 2.3),但不知道它是否仍然有效。