8

Or thinking the interceptor for this scenario applicable ?

Our app using OkHttp for downloading files (new version of app, daily databases etc.)

Sometimes server fails just while the app streaming bytes (btw the problem is, recvfrom failed: ECONNRESET)

So to fix this case i just wanted to write OkHttp retry interceptor. But seems this is appropriate for operations which aren't streaming.

Is there a solution(like interceptor) to handle this case ?


To make more clear exposition

0%==============================100% (Just started streaming)

0%==============================100% (10% completed)

0%==============================100% (20% completed)

0%==============================100% (ECONNRESET - Connection reset by peer)

At just this point, streaming gets stopped. The thing i'm wishing from OkHttp is recognizing this situation then starting the stream from scratch (not from 20%)


Related code here, pay attention to comments

 Call call = client.newCall(new Request.Builder().url(url).get().build());
 Response response = call.execute();
 // PROBLEM DOES NOT OCCUR THERE
 // PROBLEM DOES NOT OCCUR THERE
 // PROBLEM DOES NOT OCCUR THERE
 if (response.code() == 200 || response.code() == 201) {
     InputStream inputStream = null;
     try {
         long downloaded = 0;
         byte[] buff = new byte[1024 * 4];
         inputStream = response.body().byteStream();
         long target = response.body().contentLength();
         while (true) {
             // EXCEPTION OCCURS THERE
             // EXCEPTION OCCURS THERE
             // EXCEPTION OCCURS THERE
             int read = inputStream.read(buff);
             if (read == -1) {
                 break;
             }
             downloaded += read;
         }
         ...
     } catch (IOException e) {
         // EXCEPTION SAYS 
         // ECONNRESET - Connection reset by peer
         ...
     }
}
blackkara
  • 4,900
  • 4
  • 28
  • 58

3 Answers3

1

You can write a custom Interceptor like below:

OkHttp has Interceptors. You need a custom Interceptor like one below:

public class CustomResponseInterceptor implements Interceptor {

    private final String TAG = getClass().getSimpleName();

    @Override
    public Response intercept(Object object) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
        if (response.code() != 200//Your error code here,) {
           //Cancel your Request here
            return something;
        }
        Log.d(TAG, "INTERCEPTED:$ " response.toString());
        return response;
    }

The code shown is extracted from this Medium Article on Interceptors.
You can also look at this library which implements Retry Interceptors, But you can modify it for your use.

Paraskevas Ntsounos
  • 1,755
  • 2
  • 18
  • 34
Ganesh
  • 368
  • 5
  • 15
  • This is not answer of question because it's already mentioned that the usual retry(for cases not 200) interceptor was intended to make request again. I emphasized the point of streaming case. – blackkara May 10 '18 at 09:17
  • I said instead of Retrying, you can simply cancel your request in the retry part, I'm not sure if it was the right idea or not. – Ganesh May 10 '18 at 09:19
  • 1
    Did you point intercept callback of interceptor by saying 'retry part' ? If yes then what's the proper way of handling `ECONNRESET - Connection reset by peer` inside this ? I'm asking because exception appears in streaming part `inputStream.read(buff);` not `call.execute()` – blackkara Jul 06 '18 at 10:52
1

When ECONNRESET - Connection reset by peer occurs why don't you cancel your ongoing call in your catch block and start a new network call for the same file

catch (IOException e) {
         // EXCEPTION SAYS 
         // ECONNRESET - Connection reset by peer
         ...
         call.cancel();//something like this
         startDownloadingFromScratch();//new network request to start from scratch  
     }
Vicky
  • 1,807
  • 5
  • 23
  • 34
  • We could also make a workaround for cases of not 200(or 201) after `response.code() == 200 || response.code() == 201`, but we use interceptor mechanism instead! Same thing, the question searches a way which has taste of interceptors. – blackkara Jul 06 '18 at 09:05
-1

Try this.

OkHttpClient client = new OkHttpClient();
    client.setConnectTimeout(CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
    client.setReadTimeout(READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
    client.interceptors().add(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();

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

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

                Log.d("intercept", "Request is not successful - " + tryCount);

                tryCount++;

                // retry the request
                response = chain.proceed(request);
            }

            // otherwise just pass the original response on
            return response;
        }
    });

set this client as your retrofit client.

new Retrofit.Builder()
    ...other codes
    .client(client)
    ...other codes
    .build();

Good luck.

Tharindu Welagedara
  • 2,660
  • 18
  • 27
  • The `isSuccessful` method is reminiscent of checking response code equals 200. So this approach does not help to detect data stream is interrupted due to bad scenarios. Sorry, this answer is almost same with @Ganesh's – blackkara May 12 '18 at 15:25
  • i think this code might throw error: to close the previous response first then you can proceed with making new request. – Ahmad Shahwaiz Aug 16 '21 at 08:26