As this should be purely functional I put together this limiter class (as of now it might contain bugs since I couldn't use it yet but you get the idea). But how do I actually use it? I went ahead and tried to write a client middleware as per http4s' documentation but the types just don't work out, IIUC for middleware I should use Client.run
but I can't suspend that code in IO.
class Limiter(using clock: Clock[IO])(
private val requestsLeft: IO[AtomicCell[IO, Int]],
private val resetAt: IO[AtomicCell[IO, FiniteDuration]]
):
def update(currentRequestsLeft: Int, currentResetAt: Int) =
for
requestsLeft <- requestsLeft
resetAt <- resetAt
_ <- requestsLeft.set(currentRequestsLeft)
_ <- resetAt.set(FiniteDuration(currentResetAt, SECONDS))
yield ()
def delay[T](effect: IO[T]) =
val delay = for
requestsLeft <- requestsLeft.flatMap(_.get)
resetAt <- resetAt.flatMap(_.get)
currentTime <- clock.realTime
delay <- if requestsLeft <= 0 then IO.sleep(resetAt - currentTime) else IO.unit
yield delay
delay >> effect
end delay
end Limiter