-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ConcurrentRateLimiter] Redis backend (#39)
- Loading branch information
Showing
99 changed files
with
3,203 additions
and
131 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
modules/core/src/main/scala/genkai/ConcurrentRateLimiter.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package genkai | ||
|
||
import java.time.Instant | ||
|
||
/** | ||
* @tparam F - effect type | ||
*/ | ||
trait ConcurrentRateLimiter[F[_]] extends MonadErrorAware[F] { | ||
|
||
final def use[A: Key, B](key: A)(f: => F[B]): F[Either[ConcurrentLimitExhausted[A], B]] = | ||
use(key, Instant.now())(f) | ||
|
||
private[genkai] def use[A: Key, B](key: A, instant: Instant)( | ||
f: => F[B] | ||
): F[Either[ConcurrentLimitExhausted[A], B]] | ||
|
||
def reset[A: Key](key: A): F[Unit] | ||
|
||
final def acquire[A: Key](key: A): F[Boolean] = | ||
acquire(key, Instant.now()) | ||
|
||
private[genkai] def acquire[A: Key]( | ||
key: A, | ||
instant: Instant | ||
): F[Boolean] | ||
|
||
final def release[A: Key](key: A): F[Boolean] = | ||
release(key, Instant.now()) | ||
|
||
private[genkai] def release[A: Key]( | ||
key: A, | ||
instant: Instant | ||
): F[Boolean] | ||
|
||
final def permissions[A: Key](key: A): F[Long] = permissions(key, Instant.now()) | ||
|
||
private[genkai] def permissions[A: Key](key: A, instant: Instant): F[Long] | ||
|
||
def close(): F[Unit] | ||
} |
10 changes: 10 additions & 0 deletions
10
modules/core/src/main/scala/genkai/ConcurrentRateLimiterError.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package genkai | ||
|
||
sealed abstract class ConcurrentRateLimiterError(msg: String, cause: Throwable) | ||
extends RuntimeException(msg, cause) | ||
|
||
final case class ConcurrentLimitExhausted[A: Key](key: A) | ||
extends ConcurrentRateLimiterError(s"No available slots for key: ${Key[A].convert(key)}", null) | ||
|
||
final case class ConcurrentRateLimiterClientError(cause: Throwable) | ||
extends ConcurrentRateLimiterError(cause.getLocalizedMessage, cause) |
14 changes: 14 additions & 0 deletions
14
modules/core/src/main/scala/genkai/ConcurrentStrategy.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package genkai | ||
|
||
import scala.concurrent.duration.Duration | ||
|
||
sealed trait ConcurrentStrategy | ||
|
||
object ConcurrentStrategy { | ||
|
||
/** | ||
* @param slots - available slots for concurrent requests | ||
* @param ttl - default ttl for automatic slot acquisition cleanup if manual cleanup did not succeed | ||
*/ | ||
final case class Default(slots: Long, ttl: Duration) extends ConcurrentStrategy | ||
} |
48 changes: 48 additions & 0 deletions
48
modules/core/src/main/scala/genkai/EitherConcurrentRateLimiter.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package genkai | ||
|
||
import java.time.Instant | ||
import genkai.monad.{EitherMonadError, MonadError} | ||
|
||
class EitherConcurrentRateLimiter(concurrentRateLimiter: ConcurrentRateLimiter[Identity]) | ||
extends ConcurrentRateLimiter[Either[Throwable, *]] { | ||
type ResultRight[A, B] = Either[ConcurrentLimitExhausted[A], B] | ||
type Result[A, B] = Either[Throwable, ResultRight[A, B]] | ||
|
||
override private[genkai] def use[A: Key, B](key: A, instant: Instant)( | ||
f: => Either[Throwable, B] | ||
): Result[A, B] = | ||
monadError.eval(concurrentRateLimiter.use(key, instant)(f)).flatMap { | ||
case Left(value) => | ||
Right[Throwable, ResultRight[A, B]](Left[ConcurrentLimitExhausted[A], B](value)) | ||
case Right(value) => | ||
value match { | ||
case Left(value) => Left(value) | ||
case Right(value) => Right(Right(value)) | ||
} | ||
} | ||
|
||
override def reset[A: Key](key: A): Either[Throwable, Unit] = | ||
monadError.eval(concurrentRateLimiter.reset(key)) | ||
|
||
override private[genkai] def acquire[A: Key]( | ||
key: A, | ||
instant: Instant | ||
): Either[Throwable, Boolean] = | ||
monadError.eval(concurrentRateLimiter.acquire(key, instant)) | ||
|
||
override private[genkai] def release[A: Key]( | ||
key: A, | ||
instant: Instant | ||
): Either[Throwable, Boolean] = | ||
monadError.eval(concurrentRateLimiter.release(key, instant)) | ||
|
||
override private[genkai] def permissions[A: Key]( | ||
key: A, | ||
instant: Instant | ||
): Either[Throwable, Long] = | ||
monadError.eval(concurrentRateLimiter.permissions(key, instant)) | ||
|
||
override def close(): Either[Throwable, Unit] = monadError.eval(concurrentRateLimiter.close()) | ||
|
||
override def monadError: MonadError[Either[Throwable, *]] = EitherMonadError | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package genkai | ||
|
||
import genkai.monad.MonadError | ||
|
||
trait MonadErrorAware[F[_]] { | ||
def monadError: MonadError[F] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
modules/core/src/main/scala/genkai/TryConcurrentRateLimiter.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package genkai | ||
|
||
import java.time.Instant | ||
|
||
import genkai.monad.{MonadError, TryMonadError} | ||
|
||
import scala.util.{Failure, Success, Try} | ||
|
||
final class TryConcurrentRateLimiter(concurrentRateLimiter: ConcurrentRateLimiter[Identity]) | ||
extends ConcurrentRateLimiter[Try] { | ||
override private[genkai] def use[A: Key, B](key: A, instant: Instant)( | ||
f: => Try[B] | ||
): Try[Either[ConcurrentLimitExhausted[A], B]] = | ||
monadError.eval(concurrentRateLimiter.use(key, instant)(f)).flatMap { | ||
case Left(value) => Success(Left(value)) | ||
case Right(value) => | ||
value match { | ||
case Failure(exception) => Failure(exception) | ||
case Success(value) => Success(Right(value)) | ||
} | ||
} | ||
|
||
override private[genkai] def acquire[A: Key]( | ||
key: A, | ||
instant: Instant | ||
): Try[Boolean] = | ||
monadError.eval(concurrentRateLimiter.acquire(key, instant)) | ||
|
||
override def reset[A: Key](key: A): Try[Unit] = monadError.eval(concurrentRateLimiter.reset(key)) | ||
|
||
override private[genkai] def release[A: Key]( | ||
key: A, | ||
instant: Instant | ||
): Try[Boolean] = | ||
monadError.eval(concurrentRateLimiter.release(key, instant)) | ||
|
||
override private[genkai] def permissions[A: Key](key: A, instant: Instant): Try[Long] = | ||
monadError.eval(concurrentRateLimiter.permissions(key, instant)) | ||
|
||
override def close(): Try[Unit] = monadError.eval(concurrentRateLimiter.close()) | ||
|
||
override def monadError: MonadError[Try] = TryMonadError | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.