A dispatcher decides where work should run; this example models dispatching as a deterministic queue of labels.

dispatcher A dispatcher chooses an execution lane. This page models lanes as plain strings so replay stays deterministic.

Dispatcher Queue Model

lane
DispatcherQueueModel.kt
Replay: real traced execution (multi-file project)
import kotlin.coroutines.Continuation
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.startCoroutine

suspend fun dispatch(lane: String, task: String): String {
    return "$lane:$task"
}

fun main() {
    val lane = "main"
    val queue = mutableListOf("parse", "render", "publish")
    val handled = mutableListOf<String>()

    val work: suspend () -> String = {
        for (task in queue) {
            handled.add(dispatch(lane, task))
        }
        handled.joinToString(",")
    }

    work.startCoroutine(object : Continuation<String> {
        override val context = EmptyCoroutineContext

        override fun resumeWith(result: Result<String>) {
            handled.add("complete")
        }
    })

    println("lane=$lane")
    println("handled=" + handled.joinToString(","))
}
import kotlin.coroutines.Continuation
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.startCoroutine

suspend fun dispatch(lane: String, task: String): String {
    return "$lane:$task"
}

fun main() {
    val lane = "io"
    val queue = mutableListOf("parse", "render", "publish")
    val handled = mutableListOf<String>()

    val work: suspend () -> String = {
        for (task in queue) {
            handled.add(dispatch(lane, task))
        }
        handled.joinToString(",")
    }

    work.startCoroutine(object : Continuation<String> {
        override val context = EmptyCoroutineContext

        override fun resumeWith(result: Result<String>) {
            handled.add("complete")
        }
    })

    println("lane=$lane")
    println("handled=" + handled.joinToString(","))
}
import kotlin.coroutines.Continuation
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.startCoroutine

suspend fun dispatch(lane: String, task: String): String {
    return "$lane:$task"
}

fun main() {
    val lane = "default"
    val queue = mutableListOf("parse", "render", "publish")
    val handled = mutableListOf<String>()

    val work: suspend () -> String = {
        for (task in queue) {
            handled.add(dispatch(lane, task))
        }
        handled.joinToString(",")
    }

    work.startCoroutine(object : Continuation<String> {
        override val context = EmptyCoroutineContext

        override fun resumeWith(result: Result<String>) {
            handled.add("complete")
        }
    })

    println("lane=$lane")
    println("handled=" + handled.joinToString(","))
}
  1. lane ← main, queue ← [parse, render, publish], handled ← [], work ← () -> kotlin.String

    9fun main() {10    val lane→ main = "main" //@lane="io", "default"11    val queue→ [parse, render, publish] = mutableListOf("parse", "render", "publish")12    val handled→ [] = mutableListOf<String>()1314    val work→ () -> kotlin.String: suspend () -> String = {15        for (task in queue) {16            handled.add(dispatch(lane, task))17        }18        handled.joinToString(",")19    }2021    work() -> kotlin.String.startCoroutine(object : Continuation<String> {22        override val context = EmptyCoroutineContext2324        override fun resumeWith(result: Result<String>) {25            handled.add("complete")26        }27    })
  2. suspend fun dispatch(lane: String, task: String): String

    pass 1 of 3
    5suspend fun dispatch(lanemain: String, taskparse: String): String {6    return "$lanemain:$taskparse"7}
    All 3 passes — pass 1 is the card above
    passtask
    1parse
    2render
    3publish
  3. handled.add(dispatch(lane, task))

    15for (task in queue) {16    handled.add(dispatch(lane, task))17}
  4. handled.add(dispatch(lane, task))

    15for (task in queue) {16    handled.add(dispatch(lane, task))17}
  5. handled.add(dispatch(lane, task))

    15for (task in queue) {16    handled.add(dispatch(lane, task))17}
  6. override fun resumeWith(result: Result<String>)

    21work() -> kotlin.String.startCoroutine(object : Continuation<String> {22    override val context = EmptyCoroutineContext2324    override fun resumeWith(resultSuccess(main:parse,main:render,main:publish): Result<String>) {25        handled[main:parse, main:render, main:publish].add("complete")26    }27})
  7. println("lane=$lane")

    29    println("lane=$lanemain")30    println("handled=" + handled[main:parse, main:render, main:publish, complete].joinToString(","))31}
    outputlane=main
    handled=main:parse,main:render,main:publish,complete
  1. lane ← io, queue ← [parse, render, publish], handled ← [], work ← () -> kotlin.String

    9fun main() {10    val lane→ io = "io"11    val queue→ [parse, render, publish] = mutableListOf("parse", "render", "publish")12    val handled→ [] = mutableListOf<String>()1314    val work→ () -> kotlin.String: suspend () -> String = {15        for (task in queue) {16            handled.add(dispatch(lane, task))17        }18        handled.joinToString(",")19    }2021    work() -> kotlin.String.startCoroutine(object : Continuation<String> {22        override val context = EmptyCoroutineContext2324        override fun resumeWith(result: Result<String>) {25            handled.add("complete")26        }27    })
  2. suspend fun dispatch(lane: String, task: String): String

    pass 1 of 3
    5suspend fun dispatch(laneio: String, taskparse: String): String {6    return "$laneio:$taskparse"7}
    All 3 passes — pass 1 is the card above
    passtask
    1parse
    2render
    3publish
  3. handled.add(dispatch(lane, task))

    15for (task in queue) {16    handled.add(dispatch(lane, task))17}
  4. handled.add(dispatch(lane, task))

    15for (task in queue) {16    handled.add(dispatch(lane, task))17}
  5. handled.add(dispatch(lane, task))

    15for (task in queue) {16    handled.add(dispatch(lane, task))17}
  6. override fun resumeWith(result: Result<String>)

    21work() -> kotlin.String.startCoroutine(object : Continuation<String> {22    override val context = EmptyCoroutineContext2324    override fun resumeWith(resultSuccess(io:parse,io:render,io:publish): Result<String>) {25        handled[io:parse, io:render, io:publish].add("complete")26    }27})
  7. println("lane=$lane")

    29    println("lane=$laneio")30    println("handled=" + handled[io:parse, io:render, io:publish, complete].joinToString(","))31}
    outputlane=io
    handled=io:parse,io:render,io:publish,complete
  1. lane ← default, queue ← [parse, render, publish], handled ← []

    9fun main() {10    val lane→ default = "default"11    val queue→ [parse, render, publish] = mutableListOf("parse", "render", "publish")12    val handled→ [] = mutableListOf<String>()1314    val work→ () -> kotlin.String: suspend () -> String = {15        for (task in queue) {16            handled.add(dispatch(lane, task))17        }18        handled.joinToString(",")19    }2021    work() -> kotlin.String.startCoroutine(object : Continuation<String> {22        override val context = EmptyCoroutineContext2324        override fun resumeWith(result: Result<String>) {25            handled.add("complete")26        }27    })
  2. suspend fun dispatch(lane: String, task: String): String

    pass 1 of 3
    5suspend fun dispatch(lanedefault: String, taskparse: String): String {6    return "$lanedefault:$taskparse"7}
    All 3 passes — pass 1 is the card above
    passtask
    1parse
    2render
    3publish
  3. handled.add(dispatch(lane, task))

    15for (task in queue) {16    handled.add(dispatch(lane, task))17}
  4. handled.add(dispatch(lane, task))

    15for (task in queue) {16    handled.add(dispatch(lane, task))17}
  5. handled.add(dispatch(lane, task))

    15for (task in queue) {16    handled.add(dispatch(lane, task))17}
  6. override fun resumeWith(result: Result<String>)

    21work() -> kotlin.String.startCoroutine(object : Continuation<String> {22    override val context = EmptyCoroutineContext2324    override fun resumeWith(resultSuccess(default:parse,default:render,default:publish): Result<String>) {25        handled[default:parse, default:render, default:publish].add("complete")26    }27})
  7. println("lane=$lane")

    29    println("lane=$lanedefault")30    println("handled=" + handled[default:parse, default:render, default:publish, complete].joinToString(","))31}
    outputlane=default
    handled=default:parse,default:render,default:publish,complete