Skip to content

Instantly share code, notes, and snippets.

@kojilin
Last active July 11, 2025 01:39
Show Gist options
  • Select an option

  • Save kojilin/3fbb5a27563c2ba409f01e41fd4c08ab to your computer and use it in GitHub Desktop.

Select an option

Save kojilin/3fbb5a27563c2ba409f01e41fd4c08ab to your computer and use it in GitHub Desktop.
package com.example
import io.ktor.server.application.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asContextElement
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
import kotlin.random.Random
val threadLocal = ThreadLocal<String>()
fun Application.configureRouting() {
routing {
get("/") {
require(TransactionManager.currentOrNull() == null) { "1 - transaction should not exist at the start" }
newSuspendedTransaction {
require(TransactionManager.currentOrNull() != null) { "2 - transaction should exist now" }
delay(200)
require(TransactionManager.currentOrNull() != null) { "3 - transaction should exist after resume" }
}
require(TransactionManager.currentOrNull() == null) { "4 - transaction should not exist at the end" }
call.respondText("Hello World!")
}
get("/foo") {
require(threadLocal.get() == null) { "1 - thread local should not exist at the start" }
withContext(threadLocal.asContextElement(Random.nextInt(100).toString())) {
require(threadLocal.get() != null) { "2 - thread local should exist now" }
delay(200)
require(threadLocal.get() != null) { "3 - thread local should exist after resume" }
}
require(threadLocal.get() == null) { "4 - thread local should not exist outside the withContext" }
call.respondText("Hello World!")
}
// With Dispatchers.IO
get("/bar") {
require(threadLocal.get() == null) { "1 - thread local should not exist at the start" }
withContext(
Dispatchers.IO +
threadLocal.asContextElement(Random.nextInt(100).toString())
) {
require(threadLocal.get() != null) { "2 - thread local should exist now" }
delay(200)
require(threadLocal.get() != null) { "3 - thread local should exist after resume" }
}
require(threadLocal.get() == null) { "4 - thread local should not exist outside the withContext" }
call.respondText("Hello World!")
}
}
}
/
500: java.lang.IllegalArgumentException: 4 - transaction should not exist at the end
/foo
Hello World!
/bar
Hello World!
/
500: java.lang.IllegalArgumentException: 4 - transaction should not exist at the end
/foo
Hello World!
/bar
Hello World!
/
Hello World!
/foo
Hello World!
/bar
Hello World!
/
500: java.lang.IllegalArgumentException: 3 - transaction should exist after resume
/
500: java.lang.IllegalArgumentException: 1 - transaction should not exist at the start // 2nd call
/foo
500: java.lang.IllegalArgumentException: 3 - thread local should exist after resume
/bar
500: java.lang.IllegalArgumentException: 4 - thread local should not exist outside the withContext
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment