Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Okhttp ignores Dispatcher setting when used with Retrofit RxJavaCallAdapterFactory

Consider the following initializations of OkHttp and Retrofit:

public static SomeServiceRestInterface newRestService(String apiUrl) {
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(apiUrl)
                    .client(createOkHttpClient())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))
                    .addConverterFactory(createGsonConverter())
                    .build();
            return retrofit.create(SomeServiceRestInterface.class);
}

private static OkHttpClient createOkHttpClient() {
                    Dispatcher dispatcher = new Dispatcher();
                    dispatcher.setMaxRequestsPerHost(1);
                    dispatcher.setMaxRequests(1);
                    OkHttpClient.Builder builder = new OkHttpClient.Builder()
                                .dispatcher(dispatcher).build()
}

When testing the rest calls, I've noticed that Okhttp doesn't honor the setMaxRequestsPerHost or setMaxRequests settings at all. Here is the log of 3 requests dispatched simultaneously:

23/07 04:14:22.668 [RxIoScheduler-4] DEBUG - --> POST https://XXX/1 http/1.1
23/07 04:14:22.668 [RxIoScheduler-4] DEBUG - Content-Length: 0
23/07 04:14:22.668 [RxIoScheduler-4] DEBUG - --> END POST (0-byte body)
23/07 04:14:22.672 [RxIoScheduler-7] DEBUG - --> POST https://XXX/2 http/1.1
23/07 04:14:22.673 [RxIoScheduler-7] DEBUG - Content-Length: 0
23/07 04:14:22.673 [RxIoScheduler-7] DEBUG - --> END POST (0-byte body)
23/07 04:14:22.676 [RxIoScheduler-6] DEBUG - --> POST https://XXX/3 http/1.1
23/07 04:14:22.677 [RxIoScheduler-6] DEBUG - Content-Length: 0
23/07 04:14:22.677 [RxIoScheduler-6] DEBUG - --> END POST (0-byte body)

where XXX is the same domain, 1/2/3 are different paths.

I'm not sure why but I thought this possibly has to do with the RxJava Scheduler set in addCallAdapterFactory.

Is this a bug? or am I missing something?

I'm using okhttp 3.4.1, and retrofit 2.1.0.

like image 676
sahar Avatar asked Jul 23 '16 13:07

sahar


2 Answers

To quote Jake Wharton on this issue:

The implementation of Observable for Retrofit executes requests synchronously relying on the applied Scheduler for any necessarily limiting. If you need the limits from OkHttp's Dispatcher to be honored, then you'll have to write a custom CallAdapter for Observable which uses Call.enqueue instead of Call.execute.

We currently have no plans to support this, although it's likely that Retrofit v3 built on a hypothetical OkHttp v4 might make this the default (though this is a long way off).

This is the same behavior you would see if you used Retrofit's Call and called .execute(), or even used OkHttp's Call with its .execute().

like image 174
sahar Avatar answered Nov 15 '22 19:11

sahar


As of retrofit 2.9, the method createAsync() of both RxJavaCallAdapterFactory and RxJava2CallAdapterFactory creates CallAdapter that uses Call.enqueue. This delegates the queuing to OkHTTP's Dispatcher so the maxRequest settings work.

create() and createWithScheduler() will skip the Dispatcher by using Call.execute.

For RxJava3CallAdapterFactory, the names were swapped: create() is now the async adapter, while the previous direct-execute version was renamed to createSynchronous()

like image 35
Agent_L Avatar answered Nov 15 '22 19:11

Agent_L