question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Coroutine-variant is throwing while blocking equivalent is not

See original GitHub issue

I’m implementing some kind of custom caching. Because of this 304 is an interesting response for me. When getting the Triple from .response() I correctly get a Result, which is a failure. When using .awaitResponse() the continuation is throwing instead. Of course I could try-catch the FuelError, but I believe changing Fuels behaviour so that the coroutine-case matches the default case makes more sense.

My code looks like this:

class CachedHttpLineSource(private val prefs: Prefs, private val uri: String, private val userName: String, private val password: String, private val cacheDir: File) : LineSource() {
    @Serializable
    data class CachedFile(val uri: String, val etag: String?, val savedPath: String)

    private fun getDownloadRequest(etag: String? = null): Request {
        val req = Fuel.download(uri).authenticate(userName, password)
        if (etag == null) return req
        return req.header("If-None-Match" to etag)
    }

    private suspend fun download(etag: String? = null): CachedFile {
        val file = File(cacheDir, uri.sha1())
        if (file.exists()) file.delete()
        val triple = getDownloadRequest(etag).destination { _, _ -> file }.awaitResponse() // does throw here
        val response = triple.second
        val result =  triple.third
        when (result) {
            is Result.Failure -> { throw(result.getException()) } // should throw here
            is Result.Success -> { return CachedFile(uri, response.headers["ETag"]?.firstOrNull(), file.absolutePath) }
        }
    }
}

Looking into Coroutines.kt reveals the problem. Using fold for all cases instead of just returning the Triple seems wrong. As far as I understand it could work to just remove the folding and resume with the Triple in any case as the .third.get() should throw the exception in the relevant cases too.

// line 23
    response(deserializable) { request: Request, response: Response, result: Result<T, FuelError> ->
        result.fold({
            continuation.resume(Triple(request, response, result))
        }, {
            continuation.resumeWithException(it.exception)
        })
    }
    
// line 32
suspend fun Request.awaitResponse(): Triple<Request, Response, Result<ByteArray, FuelError>> =
        await(byteArrayDeserializer())
        
// line 43
suspend fun Request.awaitResponseResult(): ByteArray = awaitResponse().third.get()

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:6

github_iconTop GitHub Comments

2reactions
lucasvalentedscommented, Jul 7, 2018

@georg-jung The pull request #373 has been merged and should solve this issue.

2reactions
lucasvalentedscommented, Jun 12, 2018

@D-A-R Now I see what you mean there. Thank you for the clarification. So it seems that it’s related to the other issue.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Exceptions in coroutines. Cancellation and Exceptions in…
When a coroutine fails with an exception, it will propagate said exception up to its parent! Then, the parent will 1) cancel the...
Read more >
Coroutines (C++20) - cppreference.com
A coroutine is a function that can suspend execution to be resumed later. Coroutines are stackless: they suspend execution by returning to the...
Read more >
Are Kotlin Coroutines Enough to Replace RxJava? - JVM Advent
Both are a stream of 0..N events and the main difference between the two is that the Flowable is backpressure aware while the...
Read more >
C++ Coroutines: Understanding Symmetric Transfer
Assume we have a simple task type that lazily executes the body when another coroutine awaits it. This particular task type does not...
Read more >
Kotlin Coroutines vs Java Virtual Threads — A good story, but ...
When Kotlin came to the scene I was almost immediately sold out to the idea of it being ... Other IO operations are...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found