in teamcity-rest-client-impl/src/main/kotlin/org/jetbrains/teamcity/rest/coroutines/implementation.kt [87:141]
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
var nextDelay = initialDelayMs
var attempt = 1
while (true) {
var error: IOException? = null
val response: Response? = try {
chain.proceed(request)
} catch (e: IOException) {
error = e
null
}
// response is OK
if (response != null && !response.retryRequired()) {
return response
}
// attempt limit exceeded
if (attempt == maxAttempts) {
if (response != null) {
return response
}
throw TeamCityConversationException("Request ${request.url} failed, tried $maxAttempts times", error)
}
// log error end retry
if (response != null) {
LOG.warn(
"Request ${request.method} ${request.url} failed: HTTP code ${response.code}, " +
"attempt=$attempt, will retry in $nextDelay ms"
)
} else {
LOG.warn(
"Request ${request.method} ${request.url} failed, attempt=$attempt, will retry in $nextDelay ms",
error
)
}
if (nextDelay != 0L) {
Thread.sleep(nextDelay)
}
val nextRawDelay = minOf(nextDelay * expBackOffFactor, maxDelayMs)
// (2 * random.nextDouble() - 1.0) -> between -1 and 1
val jitter = ((2 * random.nextDouble() - 1) * nextRawDelay * expBackOffJitter).roundToLong()
nextDelay = nextRawDelay + jitter
// if not closed, next `chain.proceed(request)` will fail with error:
// `cannot make a new request because the previous response is still open: please call response.close()`
response?.close()
attempt++
}
}