Genkai (jp. 限界, limit) is a small library which allows you to limit requests or function calls.
libraryDependencies ++= Seq(
"com.nryanov.genkai" %% "<genkai-module>" % "[version]"
)
- Token bucket
- Fixed window
- Sliding window
Description of each of them can be found here: https://cloud.google.com/solutions/rate-limiting-strategies-techniques
All strategies are cost-based.
The main structure and some abstractions are similar to sttp. If you familiar with it then you should be comfortable with this library too :)
There are integrations for Monix, cats-effect and ZIO.
It is not necessary to use these integrations. There are also built-in Identity
, Try
, Either
and Future
wrappers.
Backend | Client |
---|---|
Aerospike | aerospike-client-java |
Redis | jedis lettuce redisson |
RateLimiter
Class | Effect |
---|---|
TryRateLimiter |
scala.util.Try |
EitherRateLimiter |
Either |
AerospikeSyncRateLimiter |
None (Identity ) |
AerospikeCatsRateLimiter |
F[_]: cats.effect.Sync: cats.effect.ContextShift |
AerospikeZioRateLimiter |
zio.Task |
JedisClusterSyncRateLimiter |
None (Identity ) |
JedisClusterCatsRateLimiter |
F[_]: cats.effect.Sync: cats.effect.ContextShift |
JedisClusterCats3RateLimiter |
F[_]: cats.effect.Sync |
JedisClusterZioRateLimiter |
zio.Task |
JedisSyncRateLimiter (sentinel/pool) |
None (Identity ) |
JedisCatsRateLimiter (sentinel/pool) |
F[_]: cats.effect.Sync: cats.effect.ContextShift |
JedisCats3RateLimiter (sentinel/pool) |
F[_]: cats.effect.Sync |
JedisZioRateLimiter (sentinel/pool) |
zio.Task |
LettuceSyncRateLimiter |
None (Identity ) |
LettuceAsyncRateLimiter |
scala.concurrent.Future |
LettuceCatsRateLimiter |
F[_]: cats.effect.Sync: cats.effect.ContextShift |
LettuceCatsAsyncRateLimiter |
F[_]: cats.effect.Concurrent |
LettuceCats3RateLimiter |
F[_]: cats.effect.Sync |
LettuceCats3AsyncRateLimiter |
F[_]: cats.effect.Async |
LettuceMonixAsyncRateLimiter |
monix.eval.Task |
LettuceZioRateLimiter |
zio.Task |
LettuceZioAsyncRateLimiter |
zio.Task |
RedissonSyncRateLimiter |
None (Identity ) |
RedissonAsyncRateLimiter |
scala.concurrent.Future |
RedissonCatsRateLimiter |
F[_]: cats.effect.Sync: cats.effect.ContextShift |
RedissonCatsAsyncRateLimiter |
F[_]: cats.effect.Concurrent |
RedissonCats3RateLimiter |
F[_]: cats.effect.Sync |
RedissonCats3AsyncRateLimiter |
F[_]: cats.effect.Async |
RedissonMonixAsyncRateLimiter |
monix.eval.Task |
RedissonZioRateLimiter |
zio.Task |
RedissonZioAsyncRateLimiter |
zio.Task |
ConcurrentRateLimiter
Class | Effect |
---|---|
TryConcurrentRateLimiter |
scala.util.Try |
EitherConcurrentRateLimiter |
Either |
JedisClusterSyncConcurrentRateLimiter |
None (Identity ) |
JedisClusterCatsConcurrentRateLimiter |
F[_]: cats.effect.Sync: cats.effect.ContextShift |
JedisClusterCats3ConcurrentRateLimiter |
F[_]: cats.effect.Sync |
JedisClusterZioConcurrentRateLimiter |
zio.Task |
JedisSyncConcurrentRateLimiter (sentinel/pool) |
None (Identity ) |
JedisCatsConcurrentRateLimiter (sentinel/pool) |
F[_]: cats.effect.Sync: cats.effect.ContextShift |
JedisCats3ConcurrentRateLimiter (sentinel/pool) |
F[_]: cats.effect.Sync |
JedisZioConcurrentRateLimiter (sentinel/pool) |
zio.Task |
LettuceSyncConcurrentRateLimiter |
None (Identity ) |
LettuceAsyncConcurrentRateLimiter |
scala.concurrent.Future |
LettuceCatsConcurrentRateLimiter |
F[_]: cats.effect.Sync: cats.effect.ContextShift |
LettuceCatsAsyncConcurrentRateLimiter |
F[_]: cats.effect.Concurrent |
LettuceCats3ConcurrentRateLimiter |
F[_]: cats.effect.Sync |
LettuceCats3AsyncConcurrentRateLimiter |
F[_]: cats.effect.Async |
LettuceMonixAsyncConcurrentRateLimiter |
monix.eval.Task |
LettuceZioConcurrentRateLimiter |
zio.Task |
LettuceZioAsyncConcurrentRateLimiter |
zio.Task |
RedissonSyncConcurrentRateLimiter |
None (Identity ) |
RedissonAsyncConcurrentRateLimiter |
scala.concurrent.Future |
RedissonCatsConcurrentRateLimiter |
F[_]: cats.effect.Sync: cats.effect.ContextShift |
RedissonCatsAsyncConcurrentRateLimiter |
F[_]: cats.effect.Concurrent |
RedissonCats3ConcurrentRateLimiter |
F[_]: cats.effect.Sync |
RedissonCats3AsyncConcurrentRateLimiter |
F[_]: cats.effect.Async |
RedissonMonixAsyncConcurrentRateLimiter |
monix.eval.Task |
RedissonZioConcurrentRateLimiter |
zio.Task |
RedissonZioAsyncConcurrentRateLimiter |
zio.Task |
import genkai._
import genkai.redis.jedis._
import redis.clients.jedis.JedisPool
object Main {
def main(args: Array[String]): Unit = {
val jedisPool = new JedisPool()
val strategy = FixedWindow(10, Window.Minute) // 10 requests per 1 minute
val rateLimiter: RateLimiter[Identity] = JedisSyncRateLimiter(jedisPool, strategy)
val key: String = "my key"
if (rateLimiter.acquire(key)) {
// some logic
} else {
// handle `too many requests`
}
}
}
More examples can be found in the examples folder.
Some methods of RateLimiter[F[_]]
trait require implicit Key
instance for your key object.
trait Key[A] {
/**
* @param value - value which will be used as unique (or not) identifier
* @return - string representation of id
*/
def convert(value: A): String
}
Key[A]
allows you to control locks. For example, if you define custom Key[String]
which always returns constant id
then it will work as a global rate limiter.
There are a number of default implementation for basic types, but it is possible to define a new one if necessary.