All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cognite.sdk.scala.sttp.RateLimitingBackend.scala Maven / Gradle / Ivy

package com.cognite.sdk.scala.sttp

import cats.effect.IO
import cats.effect.kernel.MonadCancel
import cats.effect.std.Semaphore
import cats.effect.unsafe.IORuntime
import sttp.capabilities.Effect
import sttp.client3.{Request, Response, SttpBackend}
import sttp.monad.MonadError

class RateLimitingBackend[F[_], +P] private (
    delegate: SttpBackend[F, P],
    semaphore: Semaphore[F]
)(implicit monadCancel: MonadCancel[F, Throwable])
    extends SttpBackend[F, P] {
  override def send[T, R >: P with Effect[F]](
      request: Request[T, R]
  ): F[Response[T]] =
    // This will allow only the specified number of request run in parallel
    // While it's not the smartest way to react to rate limiting, this will
    // actually respond to backpressure when used with the RetryingBackend:
    // The 503 rate limit response is retried, but with a delay. It will also
    // block the semaphore for new requests, so it will reduce the rate
    semaphore.permit.use { _ =>
      delegate.send(request)
    }

  override def close(): F[Unit] = delegate.close()
  override def responseMonad: MonadError[F] = delegate.responseMonad
}

object RateLimitingBackend {
  def apply[S](
      delegate: SttpBackend[IO, S],
      maxParallelRequests: Int
  )(implicit ioRuntime: IORuntime): RateLimitingBackend[IO, S] =
    new RateLimitingBackend[IO, S](
      delegate,
      Semaphore[IO](maxParallelRequests.toLong).unsafeRunSync()
    )
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy