Where is suspendCoroutine supposed to be used?

in this post it is said that suspend coroutines are low level primitives that are to be used to convert call backs into suspending functions.
> suspend fun < T: Any > Call < T > .exec(): CallResult < T > = suspendCoroutine {

         enqueue(object: Callback < T > {
          override fun onFailure(call: Call < T > ? , error : Throwable ? ) {
           Log.e(tag(), error ? .message)
           it.resume(ApiResponseFailure(error ? .let {
            return @let it
           }.run {
            return @run Throwable(Constants.GENERIC_ERROR_MESSAGE)
           }))
          }
          override fun onResponse(call: Call < T > ? , response : Response < T > ? ) {
           if (response ? .isSuccessful == true) {
            response.body() ? .run {
             it.resume(ApiResponseSuccess(this))
            }
           } else {
            response ? .errorBody() ?
             .run {
              it.resume(ApiResponseFailure(HttpException(response)))
             }
           }
          }
         })
        }

In the code above I am using suspend coroutine to get results from callbacks onFailure and onResponse from retrofit. Is this a correct use case for suspend coroutines? If not can you tell me how to replace the suspendCoroutine used here?

1 Like

Yes, it is.
However you have to resume always or you coroutine suspends indefinitely.

Consider the following code:

suspend fun <T> Call<T>.executeAwait(): Response<T> = suspendCancellableCoroutine { continuation ->
    check(!isExecuted())
    continuation.invokeOnCancellation { this@executeAwait.cancel() }

    enqueue(object : Callback<T> {
        override fun onFailure(call: Call<T>, error: Throwable) {
            continuation.resumeWithException(error)
        }

        override fun onResponse(call: Call<T>, response: Response<T>) {
            continuation.resume(response)
        }
    })
}
4 Likes

Thank you.