Skip to content

Instantly share code, notes, and snippets.

@sitepodmatt
Created February 28, 2019 08:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sitepodmatt/70a8561abad20a3a62b0b0b99f9f9e08 to your computer and use it in GitHub Desktop.
Save sitepodmatt/70a8561abad20a3a62b0b0b99f9f9e08 to your computer and use it in GitHub Desktop.
example.kt
import io.kotlintest.specs.StringSpec
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext
class RequestContextTest : StringSpec({
"playing with human context" {
try {
runBlocking {
val result = async("Processing web request") {
val i1 = async<String>("fetching image 1") {
launch("some off shot task somewhere deep") {
delay(20)
throw Exception("poo")
}
delay(200)
"image1"
}
val i2 = async<String>("fetching image 2") {
delay(100)
"image2"
}
i1.await() + " : " + i2.await()
}
}
} catch (ce: ContextualException) {
println(ce)
println("Job trace: " + ce.getJobTrace())
}
}
})
fun CoroutineScope.launch(aboutMsg: String, block: suspend CoroutineScope.() -> Unit): Job {
return launch {
contextMap[this.coroutineContext[Job]!!] = aboutMsg
try {
block()
} catch (t: Throwable) {
when (t) {
is ContextualException -> throw t
else -> throw ContextualException(this.coroutineContext[Job]!!, t.message!!, t)
}
}
}
}
fun <T> CoroutineScope.async(aboutMsg: String, block: suspend CoroutineScope.() -> T): Deferred<T> {
return async<T> {
contextMap[this.coroutineContext[Job]!!] = aboutMsg
try {
block()
} catch (t: Throwable) {
when (t) {a
is ContextualException -> throw t
else -> throw ContextualException(this.coroutineContext[Job]!!, t.message!!, t)
}
}
}
}
class ContextualException(val jobCause: Job, msg: String, t: Throwable) : Exception(msg, t)
// move on to somecouroutineelement maybe along side Job?
val contextMap = mutableMapOf<Job, String>()
fun ContextualException.getJobTrace(): List<String> {
var job: Job? = this.jobCause
val list = mutableListOf<String>()
while (job != null) {
list.add(contextMap[job] ?: job.toString())
job = job.getParent()
}
return list.also { it.reverse() }
}
@UseExperimental(InternalCoroutinesApi::class)
fun Job.getParent(): Job? {
return (AbstractCoroutine::class.java as Class<*>)?.getDeclaredField("parentContext")
?.also { it.isAccessible = true }?.let { it.get(this) as? CoroutineContext? }?.let { it[Job] }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment