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

Anders Sveen

11/17/2021, 10:44 AM
Probably a basic question: But we want to launch a "background" task from KTor route. We can't get KTor to return the payload before everything completes. Even if we wrap the slow part (no need for the result) and do
Copy code
launch(<http://Dispatchers.IO|Dispatchers.IO>) { ... }
It does return 200 fast, but wait with the payload till after launch completes. Any pointers on how to achieve this? 🙂
a

Aleksei Tirman [JB]

11/17/2021, 10:46 AM
So do you want to wait for a background job completion before responding?
a

Anders Sveen

11/17/2021, 10:46 AM
No, want to respond without waiting 🙂
The other stuff we need to create the actual payload is already done 🙂
a

Aleksei Tirman [JB]

11/17/2021, 10:46 AM
The
launch
call should work in that case
Please share a code example
a

Anders Sveen

11/17/2021, 10:51 AM
Copy code
post("company") {
    val company = companyService.create(call.receive<Company>())
    println("Before")
    launch(<http://Dispatchers.IO|Dispatchers.IO>) {
        companyService.slowUpdateThing()
        println("Inside")
    }
    println("After")
    call.respond(HttpStatus.OK_200, company.id)
}
We get the sequence of: • Before • After • 200OK Headers • Inside • Actual response payload
a

Aleksei Tirman [JB]

11/17/2021, 11:13 AM
The server in the following code responds immediately and prints
Inside
after some time:
Copy code
fun main() {
    embeddedServer(Netty, port = 3333) {
        install(ContentNegotiation) {
            json()
        }

        routing {
            post("company") {
                val company = call.receive<Company>()
                println("Before")
                launch(<http://Dispatchers.IO|Dispatchers.IO>) {
                    repeat(10) {
                        delay(500)
                    }
                    println("Inside")
                }
                println("After")
                call.respondText { company.x.toString() }
            }
        }
    }.start()
}

@Serializable
data class Company(val x: Int)
Maybe the problem is that
companyService
is used in both places
a

Anders Sveen

11/17/2021, 11:22 AM
Hjm, maybe. I'll have to dig down. Thanks, knowing that launch should work helps. 🙂
t

Trevor Stone

11/17/2021, 3:01 PM
You need to launch from a different coroutine scope
(not best practice) but you can try replace with GlobalScope.launch and you should see the results you're expecting
1
The correct thing to do would be to define a coroutine scope for all of these background tasks, probably with a SupervisorJob and then launch from that scope
that way you can define error handling and even cancel the scope if it is beneficial
j

Jacopo Franzoi

11/21/2021, 12:08 PM
Hello, not sure it’s completely related, but I was sharing a similar use case, with our proposed solution, and waiting for some feedback.. but didn’t received much so far.. but in case it fits your needs, we published a lightweight library for this. Hope this helps! https://kotlinlang.slack.com/archives/C0A974TJ9/p1635367313063000
a

Anders Sveen

11/21/2021, 12:27 PM
Thanks for the feedback guys. Turned out as you say that we had to do CoroutineScope(Dispatchers.IO).launch { .. }. Exactly why I am not sure, but it works. Some day I will understand CoRoutines. 😜