override fun intercept()

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++
        }
    }