3

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?

Ahmad Shahwaiz
  • 1,432
  • 1
  • 17
  • 35

4 Answers4

3

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/

1

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()
                }
            }
        } 
Ahmad Shahwaiz
  • 1,432
  • 1
  • 17
  • 35
0

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) {
Sergio Pardo
  • 774
  • 6
  • 17
  • im able to make request again with help of this line: response = chain.call().clone().execute() – Ahmad Shahwaiz Sep 05 '21 at 12:36
  • it is restricted by the status code of the response.code other than the tryCount. – Ahmad Shahwaiz Sep 05 '21 at 12:39
  • The solution on the first comment is possible, but you will end up having 3 calls to the service, if that's ok for you then perfect. – Sergio Pardo Sep 05 '21 at 13:24
  • For the restriction, I mean on the while per se, not between the first call and the call inside the while, I'm not sure of it but I think the compiler gets to see that there is no restriction to execute the while again, while if you place the response the compiler knows that it has to wait for the call to be finished before continuing with the next iteration – Sergio Pardo Sep 05 '21 at 13:25
  • i see your point, isn't it better to remove the while and just use if. please see my answer below. – Ahmad Shahwaiz Sep 05 '21 at 15:11
  • I get this error now: FATAL EXCEPTION: OkHttp Dispatcher HTTP FAILED: java.lang.IllegalArgumentException: networkResponse.networkResponse != null – Ahmad Shahwaiz Sep 05 '21 at 15:14
  • does this works in `networkInterceptor`? – mochadwi Apr 08 '22 at 04:39
0

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

Brian Brix
  • 449
  • 4
  • 12