我正在玩Lagom,它看起来很不错,但我完全迷失了一个问题。
让我说我依赖外部HTTP服务,它只允许10个请求/秒,在其他情况下甚至可以禁止:) 我用Google搜索,但没有找到任何有效的例子。我可以在无类型的actor中包装服务并为其添加速率限制器,但我不明白如何在Akka Typed或Lagom服务之上实现它。
也许有人已经解决了这个问题?谢谢!
答案 0 :(得分:3)
你想要一个token bucket。 Akka-Streams内置了Flow.throttle,但听起来你正在使用原始akka,所以不能使用它。存在token bucket implementation in Akka,但不幸的是它没有给出任何使用指导,我自己也没有使用它。
对于我自己的用例(不是Akka但是使用Scala Futures)我编写了自己的令牌桶。它允许我根据指定的限制引用Future的触发。它是针对monix调度程序编码的,但为此目的与Akka计划非常相似:
import java.util.concurrent.ConcurrentLinkedQueue
import monix.execution.Scheduler.Implicits.global
import monix.execution.atomic.AtomicInt
import scala.concurrent.{Future, Promise}
import scala.concurrent.duration._
case class RateLimiter(duration: FiniteDuration, maxInvocations: Int) {
@volatile var permits: Int = maxInvocations
val queue = new ConcurrentLinkedQueue[() => Any]()
global.scheduleAtFixedRate(duration, duration) {
this synchronized {
permits = maxInvocations
while (!queue.isEmpty && permits > 0) {
Option(queue.poll()).foreach { fun =>
permits -= 1
fun.apply()
}
}
}
}
def apply[T](f: => Future[T]): Future[T] =
this synchronized {
if (permits > 0) {
permits -= 1
f
} else {
val res = Promise[T]()
queue.add(() => { res.completeWith(f) })
res.future
}
}
}
用法是
val limiter = RateLimiter(1.second, 10)
limiter {
someWebService.asyncCall()
}