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.
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().
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With