Statelessness 02 — RequestContext RAII
The runnable companion to compendium Doc 02: a small gRPC service whose handler builds a RequestContext (RAII) on entry and takes one of three exit paths — normal return, early return, and throw — proving the destructor fires on all three.
The full source for this example lives in
examples/statelessness/02-raii/— clone the repo,cdin, and./demo.sh.
Compendium reference: Doc 02 — RAII as the foundation for safe stateful work
A deliberately small gRPC service whose only job is to make the RequestContext lifecycle visible. Where compendium Doc 02 explains why per-request state belongs in one RAII type bound to the handler’s scope, this example lets you watch it happen.
What it demonstrates
A stateless service still holds plenty of state inside a request — a
request id, a span/timer, a deadline, a per-request memory arena, a
leased resource (a stand-in for a pooled DB connection). None of it
should outlive the request. RequestContext bundles all of it into one
move-only RAII type whose lifetime is exactly the handler’s scope:
- Constructor acquires — mints the id, starts the timer, reserves
an 8 KiB
std::pmr::monotonic_buffer_resourcearena, leases a resource from a process-scoped pool. Logs[rc] acquire. - Destructor releases — returns the lease, reports the duration.
It is
noexcept, because a destructor that throws during stack unwinding callsstd::terminate. Logs[rc] release. - Move-only,
noexceptmoves — copy deleted; movesnoexcept(the guaranteestd::vectorrelies on). After a move the source is inert, so the lease releases exactly once.
The handler takes one of three exit paths, chosen by the request’s
mode field:
mode |
Path | gRPC status |
|---|---|---|
ok |
normal processing + return | OK |
reject |
early return on validation | INVALID_ARGUMENT |
throw |
throws mid-handler | INTERNAL |
The point: the destructor runs on all three. The service logs one
acquire and one matching release per request, and its
outstanding-lease counter returns to zero at shutdown. That balance is
the machine-checkable proof that RAII cleaned up — no manual cleanup,
no leaked lease, on the happy path, the early-return path, and the
exception path alike.
Running it
cd examples/statelessness/02-raii
./demo.sh # build + bring up + drive all three modes + summary
./demo.sh --keep # leave the service running afterward
./demo.sh --clean # tear down
The first build compiles the gRPC chain from source under the UBI 9 builder — several minutes on a cold Conan cache, faster than the observability demos because there’s no OpenTelemetry in the graph. Cached builds are 2-3 minutes.
CI verification: scripts/test-stateless-demo-02-raii.sh.
Where it sits in the compendium
RAII request scope is the foundation the other compendium examples build on — process-scoped wiring (Doc 04), the PMR arena (Doc 03), the connection-pool checkout (Doc 07), and graceful shutdown (Doc 09) all assume this discipline is in place.