Kotlin Coroutine Integration¶
Contents | Previous: Error Handling
After reading this chapter
This chapter distinguishes HTTP suspension, cancellation boundaries, and dispatcher boundaries in a Kotlin coroutine.
The code example comes from the Kotlin HttpClient tutorial; the coroutine bridge behavior is verified against the Kotlin public interface.
Kotlin extensions turn the Java HTTP client's CompletionStage into suspend functions. A typed response contains
status, headers, and a decoded DTO. A raw response contains status, headers, and an undecoded body. await waits for
a typed response, awaitRaw for a raw response, fetch for a decoded body, and awaitDownload for download completion.
This chapter covers why those extensions do not occupy a thread and where a coroutine resumes.
1. The CompletionStage bridge¶
await, awaitRaw, fetch, awaitDownload, and yield are suspend functions. The extensions resume the
coroutine when the CompletionStage completes, so no thread is occupied while an HTTP response is pending. yield
is the server request builder terminator that waits while retaining the current execution turn.
The tutorial below reads a typed response through the body-only suspend extension.
val first = client.get("/players/p1/profile").fetch<PlayerProfile>()
println("first request: ${first.playerId} ${first.nickname}")
This code calls fetch<PlayerProfile>() to receive the decoded PlayerProfile body without the response envelope.
2. Coroutine cancellation and HTTP cancellation¶
awaitWithoutCancellingOperation separates a coroutine wait from ownership of an HTTP operation that has already
been submitted. Cancelling the coroutine prevents that coroutine from resuming, but cancellation does not propagate
to the HTTP operation. Its retry, body reading, and client lease therefore continue under the submitted request's rules.
Cancellation boundary
Coroutine cancellation does not stop the underlying HTTP request. Timeout and response-lifetime rules establish the business boundary for stopping work.
3. Dispatcher-controlled resumption¶
After an extension completes, its continuation resumes on the calling coroutine's dispatcher. The HTTP client does
not choose a separate dispatcher. withContext defines the scope of a CPU-bound or framework operation that must
run on a different dispatcher.
This separates HTTP I/O waiting from the placement of follow-up work. Long-running work in a download sink occupies the callback's execution lane, so a sink should hand work off when further processing needs a separate coroutine boundary.
4. runBlocking in CLI code¶
Handler, actor, and spot paths call the HTTP extensions directly from suspend functions. runBlocking belongs only
in a CLI or test that deliberately occupies its calling thread. Using it in a runtime handler turns an asynchronous
wait into an occupied-thread wait.
5. Related chapters¶
- Client defaults and the complete execution model — Client and Request Lifecycle
- Error kinds and retry decisions — Error Handling