Skip to content

C++ Coroutine Integration

Contents | Previous: Error Handling

After reading this chapter

This chapter distinguishes the scheduler that executes HTTP work from the scheduler that resumes a coroutine. The response-shape example comes from the C++ HttpClient tutorial; execution placement is verified against the C++ HTTP client interface.

task_t represents a value that completes later, and co_await suspends only the current coroutine until that value is ready. A terminator is the final call that submits the request accumulated by a request builder. The HTTP client's 0.19.0 asynchronous terminators return task_t. Blocking responses in the current tutorial distinguishes the current 0.18.x tutorial. This chapter covers where that work runs and where its continuation resumes. Client and Request Lifecycle covers request and response shapes.

1. Execution and resumption

↗ 크게 보기

Under the 0.19.0 contract, async_raw(), async<T>(), fetch<T>(), and download(sink) register HTTP work with the selected execute scheduler. When the response is ready, the caller continuation and any callback run on the resume scheduler. This separates the worker that performs HTTP I/O from the worker that continues framework work.

A body_stream provider and a download sink run on the execute worker. Directly changing server handler state from either callback can cross execution lanes. Necessary work passes through a thread-safe queue or the server scheduler.

2. Coroutine scheduler selection

The .coroutines() setting changes only execution and resumption placement; it does not make an operation asynchronous.

Client setting HTTP work Continuation and callback
No setting Default execute scheduler Default resume scheduler
.coroutines() HTTP client internal scheduler Same internal scheduler
.coroutines(resume) HTTP client internal scheduler Supplied resume scheduler
.coroutines(execute, resume) Supplied execute scheduler Supplied resume scheduler

framework_resume_scheduler_t serves as the resume scheduler when execution must return to a framework lane. The adapter posts the continuation to the framework queue, so an HTTP worker does not execute framework state directly. Passing a nullptr scheduler fails client creation or the request with invalid_operation.

3. Blocking responses in the current tutorial

The currently distributed 0.18.x tutorial uses blocking terminators in its CLI. A typed response contains status, headers, and a decoded DTO. A raw response contains status, headers, and an undecoded body. A body-only call omits the response envelope and returns the decoded DTO directly.

The following code waits for typed and raw responses through submit<T>().result() and submit_raw().result(). Its 0.18.x fetch<T>() call completes synchronously.

framework/languages/cpp/tutorial/HttpClient/main.cpp
// typed keeps the envelope, raw keeps headers/body, and fetch returns only the DTO.
const auto typed = co_await client.get ("/players/p2").async<player_info_t> ();
const auto raw = co_await client.get ("/players/p2").async_raw ();
const auto fetched = co_await client.get ("/players/p2").fetch<player_info_t> ();
std::cout << "response kinds: typed " << typed.status << " raw "
          << raw.headers.at ("content-type") << " fetch " << fetched.nickname << std::endl;

The code prints the typed status, the raw content-type header, and the nickname from the body-only DTO.

4. The 0.19.0 asynchronous contract

Under the 0.19.0 contract, async<T>(), async_raw(), fetch<T>(), and download(sink) all return task_t. Runtime code combines these asynchronous terminators with co_await, so the current worker does not wait for HTTP completion. Although fetch<T>() returns only the body, it remains asynchronous.

#707 tracks convergence between the current tutorial and the 0.19.0 names and execution model. Until #707 reaches the distributed package and tutorial, the code above represents the current 0.18.x blocking behavior.

5. Blocking terminators in CLI code

submit_raw and submit<T> wait on the calling thread and return result_t. They are for a CLI and client scenario where occupying that thread is acceptable. In a framework runtime execution context, they fail immediately with invalid_operation.

Waiting for a blocking result in an HTTP callback or coroutine can prevent the execute worker from starting the next HTTP operation. Runtime code combines an asynchronous terminator with co_await.