Skip to content
This repository has been archived by the owner on Jun 6, 2019. It is now read-only.

[Question] Coroutine cancellation is not handled, right? #7

Closed
LouisCAD opened this issue Mar 15, 2018 · 14 comments
Closed

[Question] Coroutine cancellation is not handled, right? #7

LouisCAD opened this issue Mar 15, 2018 · 14 comments

Comments

@LouisCAD
Copy link

The coroutineContext is not shared with the calling coroutine, right?
Did anyone find a way to wrap these calls so cancel() is called on the returned Deferred instance if the calling coroutine is cancelled?

Also, @JakeWharton, I remember you talking about an idea on how to directly support suspend functions in Retrofit in a Tweet. Would it handle cancellation and cancel any in progress request?

@LouisCAD
Copy link
Author

Oh, it seems it's already WIP in the jakew/suspend/2018-02-16 branch, using Retrofit 2.4.0 (SNAPSHOT in the WIP latest commit), and it seems it'd handle cancellation thanks to the coroutineContext property in the Continuation interface!

@vadymhimself
Copy link

@LouisCAD can you give a usage example?

@vadymhimself
Copy link

vadymhimself commented Jun 17, 2018

@LouisCAD I asked for an example usage of the CallbackAdapter in jakew/suspend/2018-02-16 branch. I don't really understand the purpose of CallbackAdapters and how it is meant to support cancellations.

@LouisCAD
Copy link
Author

@Bolein The Continuation interface of Kotlin coroutines allows chaining callbacks, minimizing runnable instances allocation, by using a state machine, but the current version of Retrofit is not compatible. The suspend prototype allows to write adapters that work on Continuation or alike concepts.

Without this, the best you can get in regards to coroutines support is what is in this library: https://github.com/gildor/kotlin-coroutines-retrofit

@vadymhimself
Copy link

vadymhimself commented Jun 18, 2018

@LouisCAD that is still not quite what I asked.

However, I found an answer myself and feel responsible to share it with anyone interested.

This repository contains an adapter that enables the use of coroutines with Retrofit methods. The master branch contains a simple CallAdapter that converts the original Retrofit's Call<T> into a Deferred<T>, a so-called "non-blocking future". The await method must be called on a Deferred object in order for the function to be suspended.

Usage example:

@GET("weather")
fun getWeather() : Deferred<WeatherResponse>

There is another way of executing Retrofit requests by using a Callback<T>. This callback must be the last parameter in the method.

@GET("weather")
fun getWeather(callback : Callback<WeatherResponse>)

This approach to execution is limited, because it does not provide a way to cancel the request. However, this approach has something in common with the implementation of suspending functions on JVM.

@GET("weather")
suspend fun getWeather() : WeatherResponse

It turns out, that functions marked as suspend in Kotlin are compiled into JVM methods that use a sort of callbacks themselves to return the execution after completion or error. Previous Kotlin method will compile into this equivalent in Java:

@GET("weather")
@Nullable
Object getWeather(@NotNull Continuation<WeatherResponse> var1);

Continuation can be viewed as a callback that will be used by suspending function. So what @JakeWharton did by introducing CallbackAdapters is a way to use the Continuation<T> to deliver the result of the request the way we would do it with a Callback<T>.

This allows us to mark Retrofit methods as suspending functions and never explicitly await them. In addition, as @LouisCAD pointed out, such approach has an important advantage over the regular Callback<T>: it supports cancellation.

@JakeWharton please correct me if I got anything wrong.

@vadymhimself
Copy link

Currently, I can't find any signs of the cancellation support. @JakeWharton what is the status of this feature? I believe that there is no way to be notified of the Job cancellation through the Continuation interface at this moment.

@matejdro
Copy link

matejdro commented Aug 5, 2018

Don't these invokeOnCompletion calls handle cancellation?

@LouisCAD
Copy link
Author

LouisCAD commented Aug 5, 2018 via email

@matejdro
Copy link

matejdro commented Aug 5, 2018

Doesn't context get passed when you call await() method?

@LouisCAD
Copy link
Author

LouisCAD commented Aug 5, 2018 via email

@hrach
Copy link

hrach commented Aug 22, 2018

This seems like a pretty serious issue. Now when coroutines getting non-experimental it would be great to continue with the work and get CallbackAdapter to (stable) retrotif (release) to allow proper implementation for suspend and also include this lib into the retrofit itself eventually.

@JakeWharton
Copy link
Owner

Won't fix.

square/retrofit#2886

@michaldrabik
Copy link

michaldrabik commented Feb 14, 2019

I'm sorry for digging this up but as for today does it mean that Retrofit and Coroutines are unusable?

Basically if I start a network call with a coroutine and cancel it when its ongoing (AAC ViewModel is being cleared) the app crashes with an uncaught exception from the CallAdapter.

Anything I can do or just wait for the first-hand suspend support release? Cheers

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants