Ahmad Shahwaiz
Ahmad Shahwaiz

Reputation: 1502

Retrofit: How do I retry the request again from okhttp interceptor?

Ive created an interceptor. In some cases, I want to retry the request 'n' number of time how do i do this?

class NetworkErrorHandler constructor():  Interceptor {

    //Central error handling block for errors which has impact all over the app
    override fun intercept(chain: Interceptor.Chain): Response {
        val request =  chain.request()
        var response = chain.proceed(request) 

        return  
            when (response.code) {
                401 -> { 
                    response
                }
                200 ->{  
                    response
                }
                else -> { 
                        var tryCount = 0
                        while (tryCount < 3) {
                            try { 
                                response = chain.proceed(request)
                                tryCount++
                            }catch (e: java.lang.Exception){
                                tryCount++
                            }
                        }  
                    response
                }
            } 
    }
}

It gives me this error:

Suppressed: java.lang.IllegalStateException: network interceptor must call proceed() exactly once

Do I have to do this here if yes, then how?

Upvotes: 3

Views: 11695

Answers (4)

Thang Nguyen Van
Thang Nguyen Van

Reputation: 101

Use .interceptors() to use Application Interceptor instead of .networkInterceptors() which are allowed to call .proceed() more than once. enter image description here More information: https://square.github.io/okhttp/interceptors/

Upvotes: 6

Brian Brix
Brian Brix

Reputation: 479

This is how I approached it:

@Slf4j
public class HttpRetryInterceptor implements Interceptor {
    @Override
    public @NotNull Response intercept(Chain chain) throws IOException {
        log.error("Making request for the first time.");
        var request = chain.request();
        Response response = null;
        boolean responseOK = false;
        byte tryCount = 0;
        while (!responseOK && tryCount < 3) {
            try {
                Thread.sleep(5000 * tryCount);
                response = chain.proceed(request);
                log.info("Response is: {}",response);
                log.info("Response message: {}",response.message());
                responseOK = response.isSuccessful();

            }catch (Exception e){
                e.printStackTrace();
                log.error("Request was not successful: {} . Retrying." , tryCount);
            }finally{
                assert response != null;
                response.close();
                tryCount++;
            }
        }

        return response != null ? response : chain.proceed(request);
    }
}

And then I added my Interceptor to my client with something like : new OkHttpClient.Builder().addInterceptor(new HttpRetryInterceptor()).build()

Upvotes: 2

Ahmad Shahwaiz
Ahmad Shahwaiz

Reputation: 1502

So i was able to make another call from the interceptor by using this line

response.close()      
chain.call().clone().execute()
                

Full code according to the question:

//Central error handling block for errors which has impact all over the app
class NetworkErrorHandler constructor(): Interceptor {

        var tryCount = 0
        override fun intercept(chain: Interceptor.Chain): Response {
            val request = chain.request()
            var response = chain.proceed(request)

            return
            when(response.code) {
                401 - > {
                    response
                }
                200 - > {
                    response
                }
                else - > {

                    if (tryCount < 3) {
                        Thread.sleep(2000)
                        tryCount++
                        response.close()
                        chain.call().clone().execute()

                    }
                    response.newBuilder()
                    .code(401) // Whatever code
                    .body("".toResponseBody(null)) // Whatever body
                    .protocol(Protocol.HTTP_2)
                    .message("Network Error")
                    .request(chain.request())
                    .build()
                }
            }
        } 

Upvotes: 1

Sergio Pardo
Sergio Pardo

Reputation: 792

I think you guided yourself from this other question How to retry HTTP requests with OkHttp/Retrofit? (If not, I suggest you do). The problem on your code is that your while is restricted only by trycount, but not by the result of the response. Try adding the validation regarding the status of the response in there too, so it doesn't execute the .proceed method two times in parallel.

// try the request
Response response = chain.proceed(request);

int tryCount = 0;
while (!response.isSuccessful() && tryCount < 3) {

Upvotes: 0

Related Questions