kittinunf / fuel

The easiest HTTP networking library for Kotlin/Android
https://fuel.gitbook.io/documentation/
MIT License
4.56k stars 430 forks source link

fuel-coroutines does not actually perform async IO #804

Open ndcotta-bc opened 3 years ago

ndcotta-bc commented 3 years ago

Bug Report

Description

fuel-coroutines does not actually use java's async IO API - requests are launched inside a coroutine, and then the coroutine's thread is blocked until the request completes. This makes requests cancellable but not actually asynchronous.

To Reproduce

Run this snippet:

runBlocking {
    val singleThreadContext = coroutineContext
    val now = currentTimeMillis()
    launch {
        delay(1)
        val delay = currentTimeMillis() - now
        println("Got executed after $delay ms (should print before Foo and take a few ms)")
    }
    val duration = measureTimeMillis {
        "https://google.com".httpGet()
            .awaitStringResponse(scope = singleThreadContext) // thread is blocked while we await this
    }
    println("Foo: ended request in $duration ms")
}

It prints something like:

Foo: ended request in 980 ms
Got executed after 1006 ms (should print before Foo and take a few ms)

This shows how both coroutines share the single thread (runBlocking runs on 1 thread by default). While Fuel is doing the request, the thread is blocked and we cannot do any other work.

Expected behavior

When using Fuel in an async framework (like Kotlin's coroutines, or RxJava) we expect async IO. The snippet of code above should allow us to do some work while the socket waits for the response.

Additionally, https://github.com/kittinunf/fuel/issues/429 (similarly named) which was closed, does not address this issue - it is only concerned with cancelling the request when cancelling the coroutine.

iNoles commented 1 year ago

Latest Fuel 3.x snapshots use https://github.com/square/okhttp/blob/master/okhttp-coroutines/README.md that would fix this problem.