因為這應該是純功能性的,所以我將這個限制器類放在一起(到目前為止它可能包含錯誤,因為我還不能使用它,但你明白了)。但是我該如何實際使用它呢?我繼續嘗試根據 http4s 的檔案撰寫客戶端中間件,但型別不作業,我應該使用中間件的 IIUC,Client.run但我不能在 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
uj5u.com熱心網友回復:
最終編輯:作業版本,如果有人后來遇到這個尋求幫助
class Throttler(using clock: Clock[IO])(
private val requestsLeft: Ref[IO, Long],
private val resetAt: Ref[IO, FiniteDuration]
):
def update(currentRequestsLeft: Int, currentResetAt: Long) =
for
_ <- requestsLeft.set(currentRequestsLeft)
_ <- resetAt.set(currentResetAt.seconds)
yield ()
def throttle() =
for
requestsLeft <- requestsLeft.get
resetAt <- resetAt.get
currentTime <- clock.realTime
_ <- IO.println(s"remaining as seen by throttle: ${requestsLeft}")
delay <- if requestsLeft <= 0
then IO.println(s"throttling until ${resetAt}") >> IO.sleep(resetAt - currentTime)
else IO.println("not throttling")
yield delay
end Throttler
--
def throttledClient(underlying: Client[IO], throttler: Throttler) = Client[IO] { request =>
underlying.run(request).evalTap { response =>
(
for
remaining <- response.headers.get(ci"x-rate-limit-remaining").flatMap(_.head.value.toIntOption)
resetAt <- response.headers.get(ci"x-rate-limit-reset").flatMap(_.head.value.toLongOption)
yield (throttler.update(remaining, resetAt))
).sequence
}.preAllocate(throttler.throttle())
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/536742.html
