Skip to content

Phase 7b: user-supplied middleware, client interceptors, Beast graceful drain - #16

Merged
aaylward merged 2 commits into
mainfrom
claude/smithy-cpp-generator-plan-fpeqzt
Jul 7, 2026
Merged

aaylward merged 2 commits into
mainfrom
claude/smithy-cpp-generator-plan-fpeqzt

Conversation

@aaylward

@aaylward aaylward commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Second Phase 7 hardening slice: the user-supplied middleware seams (recorded in the PLAN per review feedback), client interceptors, and server-transport robustness.

Server middleware (//runtime:server)

  • smithy::server::Middleware (function<RequestHandler(RequestHandler)>) and Chain(), composing first-outermost around the plain RequestHandler every generated server already exposes — auth checks, logging, metrics wrap outside the generated router and work with any transport; no codegen involved.
  • Observe() — the built-in structured-logging/metrics hook: one callback per served request with {method, target, status, duration} and an injectable clock for deterministic tests.

Client interceptors (//runtime:client)

  • smithy::Interceptor hooks around every HTTP attempt a generated client makes: ModifyBeforeTransmit(request, attempt) mutates a fresh per-attempt copy (auth headers, tracing ids — edits never accumulate across retries or leak into the caller's request), ReadAfterTransmit(request, outcome, attempt) observes.
  • Registered on ClientConfig::interceptors, run in registration order inside SendWithRetries; generated clients pass them through (goldens regenerated).
  • A weather e2e test drives a bearer-token interceptor through the generated client against an auth-rejecting middleware chain on the generated server — both new seams exercised together across the wire.

Beast server robustness

  • Graceful drain: Stop() closes the acceptor immediately (posted onto its strand), keep-alive reads cease, and requests already read off the wire get drain_timeout_seconds (default 10) to finish writing before the thread pool is torn down. New test stops the server mid-handler and asserts the response still arrives intact.
  • Header limits: new max_header_bytes option (default 8 KiB) caps request headers alongside the existing body limit, with a rejection test.

Docs

Production guide gains interceptor and middleware sections with worked examples plus the hardened-transport summary; server guide, runtime overview, and README updated. Also carries the PLAN entry recording user-supplied middleware as a Phase 7 deliverable.

Validation

  • bazel test //... — 44/44 green locally, plus ASan+UBSan (Beast targets are CI-verified: boost sources aren't fetchable in the local sandbox)
  • out-of-tree consumer module green against the updated generator
  • regeneration byte-stable; clang-format/clang-tidy/buildifier clean

🤖 Generated with Claude Code

https://claude.ai/code/session_01WjaNFwBZxoHdqagvq8ycQf


Generated by Claude Code

claude added 2 commits July 7, 2026 11:48
…se 7

Client interceptor chain + server RequestHandler middleware as the
extension seams the logging/metrics and auth work should build on.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WjaNFwBZxoHdqagvq8ycQf
The middleware seams recorded in the PLAN, plus server-robustness work:

- runtime //runtime:server gains user-supplied middleware:
  Middleware = function<RequestHandler(RequestHandler)>, Chain()
  composing first-outermost around the handler a generated server
  exposes (works with any transport, no codegen involved), and
  Observe() — the structured-logging/metrics hook reporting
  {method, target, status, duration} per request with an injectable
  clock.

- runtime //runtime:client gains Interceptor hooks around every HTTP
  attempt a generated client makes: ModifyBeforeTransmit mutates a
  fresh per-attempt copy of the request (auth headers, tracing ids;
  edits never accumulate across retries), ReadAfterTransmit observes
  the outcome. Registered on ClientConfig::interceptors, run in order
  inside SendWithRetries; generated clients pass them through. A
  weather e2e test drives a bearer-token interceptor against an
  auth-checking middleware chain over generated code.

- BeastServerTransport: Stop() now drains — the acceptor closes
  immediately (posted onto its strand), keep-alive reads cease, and
  in-flight requests get drain_timeout_seconds (default 10) to finish
  writing before the pool is torn down; new max_header_bytes option
  caps request headers alongside the existing body limit.

- docs: production guide sections for interceptors, middleware, and
  the hardened server transport; server guide, runtime overview, and
  README updates.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WjaNFwBZxoHdqagvq8ycQf
@aaylward
aaylward merged commit 699b217 into main Jul 7, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants