Good day,

Without much hope, I decided to ask the comrades a mysterious production bug in (out of specifics, a weak and unreliable internet connection is possible).

Rarely when sending a file to the server comes up to hundreds of repeated requests from one user. the interval between requests is sometimes no more than one millisecond (which for a long time suggested an idea of ​​a server side problem). Under the conditions of Virgo and QA, the bug does not replicate.

This is the API itself:

Api{ @Multipart @POST("data/behaviour/{deviceId}/{sessionId}") Call<ResponseBody> sendBehaviourInApp(@Path("deviceId") String deviceId,@Path("sessionId") String sessionId, @Part("file\"; filename=\"data.txt\" ")RequestBody behavoirFile); 

This is a file transfer (the irrelevant places were cleared):

 public void send(Context context, RetrofitController controller, File behaviour){ Api api = controller.createInterface(Api.class, context); RequestBody fbody = RequestBody.create(MediaType.parse("plain/text"), behaviour); Call<ResponseBody> call = api.sendBehaviourInApp( NetworkManager.requestDeviceId(context), data.getId(), fbody); call.enqueue(new BehaviorRestroCallback<ResponseBody>(context)) } 

and creating the interface itself:

 public class RetrofitController { private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); private Retrofit.Builder builder; private String serverURL; public RetrofitController(String serverURL) { this.serverURL = serverURL; builder = new Retrofit.Builder() .baseUrl(serverURL) .addConverterFactory(GsonConverterFactory.create()); } private Retrofit.Builder getBuilder() { if (builder == null) { builder = new Retrofit.Builder() .baseUrl(serverURL) .addConverterFactory(GsonConverterFactory.create()); } return builder; } public <S> S createInterface(Class<S> serviceClass, Context context) { initParameters(context); Retrofit retrofit = getBuilder().client(httpClient.readTimeout(TIMEOUT, TimeUnit.SECONDS) .connectTimeout(TIMEOUT, TimeUnit.SECONDS).writeTimeout(TIMEOUT, TimeUnit.SECONDS).build()).build(); return retrofit.create(serviceClass); } private void initParameters(final Context context) { if(!inited) { cinited = true; //get system parameters String versionName = "1"; try { PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); versionName = versionToDouble(pInfo.versionName); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } final String version = versionName; final String platform = "android";// + Build.VERSION.SDK_INT; // add interceptor httpClient.addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request.Builder requestBuilder = chain.request().newBuilder(); requestBuilder.addHeader("content-type", "application/json"); requestBuilder.addHeader("platform", platform); requestBuilder.addHeader("clientVersion", version); requestBuilder.addHeader("deviceId", NetworkManager.requestDeviceId(context)); requestBuilder.addHeader("sessionId", FidoApplication.getInstance().getModel().getSessionState().getSessionId()); return chain.proceed(requestBuilder.build()); } }); } 

}

I don’t attach BehaviorRestroCallback because Response processing time would not take a millisecond. I can only say that under different conditions the class will execute the send (context, controller, behaviour) method repeatedly (possibly in another thread).

The variant that comes to mind is asynchronous sending two or more similar requests at the same time, but if even two requests sent the same file (and somehow bypassed all checks), the result would be sending a null instead of a file, but the spam file on the server has normal size.

Perhaps the creation of two interfaces through one builder is affected.

The log of this file on the server usually starts like this (immediately a file of this size spam without delay)

 2017-07-20 09:49:29.353000 "cfmsMapiWebRequestTraceFilter - Accepted request: {method=POST, path=/mapi/v2/data/behaviour/357103074752073/1500544032714, headers={content- length=641, platform=android, clientversion=2.69, sessionid=1500544032714, content-type=multipart/form-data; accept-encoding=gzip, user- agent=okhttp/3.3.0}}" 2017-07-20 09:49:29.391000 "cfmsMapiWebRequestTraceFilter - Accepted request: {method=POST, path=/mapi/v2/data/behaviour/357103074752073/1500544032714, headers={content- length=641, platform=android, clientversion=2.69, sessionid=1500544032714, content-type=multipart/form-data; accept-encoding=gzip, user- agent=okhttp/3.3.0}}" 2017-07-20 09:49:29.392000 "cfmsMapiWebRequestTraceFilter - Accepted request: {method=POST, path=/mapi/v2/data/behaviour/357103074752073/1500544032714, headers= {content-length=641, platform=android, clientversion=2.69, sessionid=1500544032714, content-type=multipart/form-data; accept- encoding=gzip, user-agent=okhttp/3.3.0}}" 2017-07-20 09:49:29.393000 "cfmsMapiWebRequestTraceFilter - Accepted request: {method=POST, path=/mapi/v2/data/behaviour/357103074752073/1500544032714, headers= {content-length=641, platform=android, clientversion=2.69, sessionid=1500544032714, content-type=multipart/form-data; accept- encoding=gzip, user-agent=okhttp/3.3.0}}" 2017-07-20 09:49:29.393000 "cfmsMapiWebRequestTraceFilter - Accepted request: {method=POST, path=/mapi/v2/data/behaviour/357103074752073/1500544032714, headers= {content-length=641, platform=android, clientversion=2.69, sessionid=1500544032714, content-type=multipart/form-data; accept- encoding=gzip, user-agent=okhttp/3.3.0}}" 2017-07-20 09:49:29.393000 "cfmsMapiWebRequestTraceFilter - Accepted request: {method=POST, path=/mapi/v2/data/behaviour/357103074752073/1500544032714, headers= {content-length=641, platform=android, clientversion=2.69, sessionid=1500544032714, content-type=multipart/form-data; accept- encoding=gzip, user-agent=okhttp/3.3.0}}" 
  • Due to other reasons, the TIMEOUT constant was set to 120 seconds, which, compared to the usual 15 seconds, is just an unreasonably big start. Sending a file is also limited to 3 attempts. There is always the possibility that somewhere there may be a mistake, but how does this explain that several dozen and even a hundred requests came at once with an interval of 1 millisecond? How can I turn off the request retry? - Arderun
  • one
    for example, via okhttpClient.setRetryOnConnectionFailure(false) - DeKaNszn
  • Thanks for the suggestion, although I'm afraid that in production we won't be able to experiment with even a small percentage of releases - Arderun

0