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

Viewed 2878

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?

4 Answers

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) {

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()
                }
            }
        } 

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()

Related