https://kotlinlang.org logo
#ktor
Title
# ktor
e

Edd

06/17/2019, 2:26 PM
Hello, I'm working with
HttpClient
which executes a long request. This call is triggered via a
post
route, which looks something like this:
Copy code
val http = HttpClient(Apache)

routing {
    post("/api/start-job") {
        <http://http.post|http.post><String>("<http://url-to-long-request>")
        call.respond(HttpStatusCode.Accepted, "job started")
    }
}
Sending a request to this route results in having to wait quite as the client makes a heavy request (it starts a job on another service). I'd like to simply send the request to
<http://url-to-long-request>
and immediately return the
202
with
"job started"
message. I could achieve this using an
Executor
and wrapping the
<http://http.post|http.post>
call, however I feel like that is not the right way to do this. Any suggestions on this?
r

ribesg

06/17/2019, 2:36 PM
If you don’t want to wait for the post response just launch the request in another coroutine using
launch { }
e

Edd

06/17/2019, 2:43 PM
Hmm doesn't seem to cut it, I'm guessing I should use a different context? Both cases yield the same result (
http
call still pauses the API):
Copy code
coroutineScope {
    launch(<http://Dispatchers.IO|Dispatchers.IO>) {
        // http stuff
    }
}

coroutineScope {
    launch {
        // http stuff
    }
}
u

uli

06/17/2019, 10:15 PM
try
GlobalScope
e

Edd

06/18/2019, 6:26 AM
Are you sure about this?
Copy code
Application code usually should use an application-defined CoroutineScope. Using async or launch on the instance of GlobalScope is highly discouraged.
From: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/
Sorry for the dumb questions, I'm having a hard time finding information on co-routines. Most cases that pop-up are related to Android dev...
u

uli

06/18/2019, 2:33 PM
You should not generally use it, as you loose control about coroutines started on GlobalScope. But in this case this seems what you requested. The scope defines the lifetime of your coroutines. If you want your coroutine to finish, no matter what and you don't want to know or wait for the completion GlobalScope is what you want. You might still question if this really is what you want
e

Edd

06/19/2019, 6:06 AM
Understood. To finish things off, I went with the following approach (I'm assuming its more or less the same as
GlobalScope
, just with a default dispatcher):
Copy code
object IOCoroutineScope : CoroutineScope by CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO> + handler)

private val log = KotlinLogging.logger { }

private val handler = CoroutineExceptionHandler { _, exception ->
    log.error("Unhandled error", exception)
}
Then, in my route handlers, I specify
CoroutineScope
and pass in
IOCoroutineScope
(so that I could pass a blocking scope in tests) and initialize them with
IOCoroutineScope
. Then on this
scope
, I do
scope.launch
and stuff happens the way I want. Also,
<http://Dispatchers.IO|Dispatchers.IO>
is used in this case, as the async stuff makes HTTP requests (to Elastcisearch). Thanks for the help!
u

uli

06/19/2019, 9:48 AM
thanks for the update