Probably a basic question: But we want to launch a...
# ktor
a
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
So do you want to wait for a background job completion before responding?
a
No, want to respond without waiting 🙂
The other stuff we need to create the actual payload is already done 🙂
a
The
launch
call should work in that case
Please share a code example
a
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
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
Hjm, maybe. I'll have to dig down. Thanks, knowing that launch should work helps. 🙂
t
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
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
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. 😜