mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-11-22 16:23:48 +00:00
small rework in ExceptionsOnlyLimiter
This commit is contained in:
parent
d83e3eb10a
commit
53800d49bf
@ -10,6 +10,7 @@
|
|||||||
exception
|
exception
|
||||||
* `EmptyLimiter` has been renamed to `ExceptionsOnlyLimiter` and currently will stop requests after
|
* `EmptyLimiter` has been renamed to `ExceptionsOnlyLimiter` and currently will stop requests after
|
||||||
`TooMuchRequestsException` happen until retry time is actual
|
`TooMuchRequestsException` happen until retry time is actual
|
||||||
|
* Now `ExceptionsOnlyLimiter` (previously `EmptyLimiter`) is a class
|
||||||
* `AbstractRequestCallFactory` currently will not look at the response and wait if it have `RetryAfter` error. New
|
* `AbstractRequestCallFactory` currently will not look at the response and wait if it have `RetryAfter` error. New
|
||||||
behaviour aimed on delegating of this work to `RequestsLimiter`
|
behaviour aimed on delegating of this work to `RequestsLimiter`
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ class KtorRequestsExecutor(
|
|||||||
client: HttpClient = HttpClient(),
|
client: HttpClient = HttpClient(),
|
||||||
callsFactories: List<KtorCallFactory> = emptyList(),
|
callsFactories: List<KtorCallFactory> = emptyList(),
|
||||||
excludeDefaultFactories: Boolean = false,
|
excludeDefaultFactories: Boolean = false,
|
||||||
private val requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter,
|
private val requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter(),
|
||||||
private val jsonFormatter: Json = nonstrictJsonFormat
|
private val jsonFormatter: Json = nonstrictJsonFormat
|
||||||
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
|
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
|
||||||
private val callsFactories: List<KtorCallFactory> = callsFactories.run {
|
private val callsFactories: List<KtorCallFactory> = callsFactories.run {
|
||||||
|
@ -2,44 +2,48 @@ package dev.inmo.tgbotapi.bot.settings.limiters
|
|||||||
|
|
||||||
import dev.inmo.micro_utils.coroutines.safely
|
import dev.inmo.micro_utils.coroutines.safely
|
||||||
import dev.inmo.tgbotapi.bot.exceptions.TooMuchRequestsException
|
import dev.inmo.tgbotapi.bot.exceptions.TooMuchRequestsException
|
||||||
import dev.inmo.tgbotapi.types.RetryAfterError
|
import dev.inmo.tgbotapi.types.*
|
||||||
import io.ktor.client.features.ClientRequestException
|
import io.ktor.client.features.ClientRequestException
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This limiter will limit requests only after getting a [RetryAfterError] from incoming [block]s. Important thing is
|
* This limiter will limit requests only after getting a [RetryAfterError] or [ClientRequestException] with
|
||||||
* that in case if some of block has been blocked, all the others will wait until it will be possible to be called
|
* [HttpStatusCode.TooManyRequests] status code. Important thing is that in case if some of block has been blocked, all
|
||||||
|
* the others will wait until it will be possible to be called
|
||||||
|
*
|
||||||
|
* @param defaultTooManyRequestsDelay This parameter will be used in case of getting [ClientRequestException] with
|
||||||
|
* [HttpStatusCode.TooManyRequests] as a parameter for delay like it would be [TooMuchRequestsException]. The reason of
|
||||||
|
* it is that in [ClientRequestException] there is no information about required delay between requests
|
||||||
*/
|
*/
|
||||||
object ExceptionsOnlyLimiter : RequestLimiter {
|
class ExceptionsOnlyLimiter(
|
||||||
|
private val defaultTooManyRequestsDelay: MilliSeconds = 1000L
|
||||||
|
) : RequestLimiter {
|
||||||
private val lockState = MutableStateFlow(false)
|
private val lockState = MutableStateFlow(false)
|
||||||
|
private suspend fun lock(timeMillis: MilliSeconds) {
|
||||||
|
try {
|
||||||
|
safely {
|
||||||
|
lockState.emit(true)
|
||||||
|
delay(timeMillis)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lockState.emit(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun <T> limit(block: suspend () -> T): T {
|
override suspend fun <T> limit(block: suspend () -> T): T {
|
||||||
while (true) {
|
while (true) {
|
||||||
lockState.first { !it }
|
lockState.first { !it }
|
||||||
val result = safely({
|
val result = safely({
|
||||||
when (it) {
|
when (it) {
|
||||||
is TooMuchRequestsException -> {
|
is TooMuchRequestsException -> {
|
||||||
try {
|
lock(it.retryAfter.leftToRetry)
|
||||||
safely {
|
|
||||||
lockState.emit(true)
|
|
||||||
delay(it.retryAfter.leftToRetry)
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lockState.emit(false)
|
|
||||||
}
|
|
||||||
Result.failure(it)
|
Result.failure(it)
|
||||||
}
|
}
|
||||||
is ClientRequestException -> {
|
is ClientRequestException -> {
|
||||||
if (it.response.status == HttpStatusCode.TooManyRequests) {
|
if (it.response.status == HttpStatusCode.TooManyRequests) {
|
||||||
try {
|
lock(defaultTooManyRequestsDelay)
|
||||||
safely {
|
|
||||||
lockState.emit(true)
|
|
||||||
delay(1000L)
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lockState.emit(false)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw it
|
throw it
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ typealias GooglePlaceId = String
|
|||||||
typealias GooglePlaceType = String
|
typealias GooglePlaceType = String
|
||||||
|
|
||||||
typealias Seconds = Int
|
typealias Seconds = Int
|
||||||
|
typealias MilliSeconds = Long
|
||||||
typealias LongSeconds = Long
|
typealias LongSeconds = Long
|
||||||
|
|
||||||
typealias Meters = Float
|
typealias Meters = Float
|
||||||
|
Loading…
Reference in New Issue
Block a user