Suppose I have an HTTP client to call a server with a request rate limit, e.g. 1000 requests/ sec. I implemented a rate limiter in ExecutionContext
like this:
Created a bounded blocking queue with RateLimiter of Guava
class MyBlockingQueue[A](capacity: Int, permitsPerSecond: Int)
extends ArrayBlockingQueue[A](capacity) {
private val rateLimiter = RateLimiter.create(permitsPerSecond.toDouble)
override def take(): A = {
rateLimiter.acquire()
super.take()
}
override def poll(timeout: Long, unit: TimeUnit): A = {
rateLimiter.tryAcquire(timeout, unit) // todo: fix it
super.poll(timeout, unit)
}
}
Created an ExecutionContext
from a ThreadPoolExecutor
with this queue.
def createRateLimitingExecutionContext(numThreads: Int,
capacity: Int,
permitsPerSecond: Int): ExecutionContext = {
val queue = new MyBlockingQueue[Runnable](capacity, permitsPerSecond)
val executor = new ThreadPoolExecutor(numThreads, numThreads, 0L, TimeUnit.MILLISECONDS, queue)
ExecutionContext.fromExecutor(executor)
}
Now I can create an ExecutionContext
with a rate limit and pass it to the client:
implicit val ec = createRateLimitingThreadPoolExecutionContext(
numThreads = 100,
capacity = 1000,
permitsPerSecond = 1000
)
httpGet("http://myserver.com/xyz") // create Futures with "ec"
Does it make sense ? How would you test this ExecutionContext
?