square / retrofit

A type-safe HTTP client for Android and the JVM
https://square.github.io/retrofit/
Apache License 2.0
42.96k stars 7.3k forks source link

Conditional retrofit's call cancellation on dispose in RxJavaCallAdapter #3376

Open danaimset opened 4 years ago

danaimset commented 4 years ago

[Feature] request Currently retrofit's call is cancelled as soon as RxJava subscription is disposed, i.e. https://github.com/square/retrofit/blob/46dc939a0dfb470b3f52edc88552f6f7ebb49f42/retrofit-adapters/rxjava2/src/main/java/retrofit2/adapter/rxjava2/CallEnqueueObservable.java#L94

Sometimes client doesn't need the result of execution right in place but the result is required later.

There is an option to mark scheduler in RxJava as interruptible or not. But continuously running thread will not allow retrofit call proceed if subscription was disposed because of call cancellation from the link above.

JakeWharton commented 4 years ago

OkHttp will interrupt the thread itself if you are using blocking requests. Can you express the problem in some kind of test case or sample that I can run? I'm not really understanding what you think the problem is in practice.

danaimset commented 4 years ago

Preconditions:

  1. I have a bunch of requests.
  2. The next one debounce(disposes) the previous one.
  3. I have OkHttpInterceptor installed to check if my access_token is expired or about to be expired. There is a synchronous logic of refreshing token inside interceptor.
  4. All synchronization logic between all requests done on interceptor's level. Every upcoming request is waiting while token is refreshing.

Problem: If one of the latest requests has started refreshing token and the next one is trying to dispose it the result of refreshing token will be lost cause call cancellation.

Of course there are multiple other approaches how to avoid this problem and let the previous API call to be cancelled. But I realized that it's kind of limitation from retrofit + rx part.

If I understand the logic of https://github.com/square/retrofit/blob/46dc939a0dfb470b3f52edc88552f6f7ebb49f42/retrofit-adapters/rxjava2/src/main/java/retrofit2/adapter/rxjava2/CallEnqueueObservable.java correctly, every time rx subscription is disposed - http call is canceled.

What if I want to dispose the subscription but keep api call running?

Let's say in Android I'm leaving an activity and dispose all the requests cause I don't need my pending APIs calling the target activity back cause it is not running any more. And I don't want to prevent pending APIs reach the server. With this sample I don't mean that API calls tied up on activity's logic and the right solution would be moving them out to Worker or something like that. It's just for demonstration purpose.

My final thoughts are the following: It makes sense to let API call continue to execute event if the subscription was disposed. I think it's strong relation between Rx and Retrofit. For example: there is an experimental API in Rx's Schedulers which allow us to control the behavior of Scheduler Worker: http://reactivex.io/RxJava/javadoc/io/reactivex/schedulers/Schedulers.html#from-java.util.concurrent.Executor-boolean-

Related question on stackoverflow: https://stackoverflow.com/questions/47794454/prevent-dispose-to-cancel-network-request

viniciusmo commented 3 years ago

@danaimset did you get any fix for that case?

@JakeWharton I have the same problem, the refresh token request is interrupted because it is triggered dispose of.