feat: axum skeleton with /health endpoint (Phase 1.b.1)#1
Conversation
First brick of RFC-001 Phase 1.b. Sets up the runtime so subsequent
PRs (1.b.2 Postgres + migrations, 1.b.3 utoipa, 1.b.4 CRUD modules)
land on a stable foundation.
What's wired:
- axum 0.8 + tokio multi-thread runtime, binds 127.0.0.1:3000 by
default (override via WAVEFLOW_BIND).
- tracing-subscriber with env-filter + JSON formatter switchable via
WAVEFLOW_LOG_FORMAT=json. Defaults are pretty + debug for the crate's
own logs + tower_http access traces.
- tower-http middleware: per-request UUID (x-request-id, echoed back),
trace layer, configurable request timeout (default 30s, the
streaming endpoint in 1.e will live on a separate router).
- Graceful shutdown on SIGINT + SIGTERM (Windows: SIGINT only).
- `Config::from_env` as the single env-reading entry point; no
`std::env` reads scattered across modules.
API surface today is just `GET /health` → `{status, version}`. Two
integration tests in `tests/health.rs` boot the real router on a
kernel-assigned port and validate the response + that the request-id
echo path works. No DB, no auth, no waveflow-core dependency yet —
those land in 1.b.2.
Signed-off-by: InstaZDLL <github.105mh@8shield.net>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds a full Axum server: example environment, dependencies, a Config loader, a ChangesAxum Server Bootstrap
Sequence DiagramsequenceDiagram
participant Client
participant Server as AxumServer
participant RequestID as RequestIdLayer
participant Tracing as TraceLayer
participant Router as APIRouter
participant Health as HealthHandler
Client->>Server: GET /health (+ optional x-request-id)
Server->>RequestID: receive request
RequestID->>RequestID: set or echo x-request-id
RequestID->>Tracing: forward request with request-id
Tracing->>Router: route request
Router->>Health: dispatch /health
Health->>Router: JSON {status:"ok", version}
Router->>Tracing: response
Tracing->>RequestID: attach tracing info
RequestID->>Server: add x-request-id header to response
Server->>Client: 200 JSON + x-request-id
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/config.rs`:
- Around line 41-47: The parsing currently allows
WAVEFLOW_REQUEST_TIMEOUT_SECS=0 which yields a zero timeout; after extracting
request_timeout_secs (the variable created by the current parse chain in
src/config.rs) validate that the final value is > 0 and return an error if it
equals 0. Concretely, after the existing parse/unwrap_or(30) expression that
assigns request_timeout_secs, add a check (or incorporate into the parsing
chain) that returns an anyhow::anyhow!("invalid WAVEFLOW_REQUEST_TIMEOUT_SECS:
must be > 0") error when request_timeout_secs == 0 so the service fails fast on
this misconfiguration.
In `@src/lib.rs`:
- Around line 45-48: Trace spans currently don't include the x-request-id
because TraceLayer::new_for_http() uses DefaultMakeSpan with
include_headers=false; replace or augment that call to use
TraceLayer::make_span_with so the created span includes the request id: either
use DefaultMakeSpan::new().include_headers(true) inside make_span_with or
implement a custom closure that reads REQUEST_ID_HEADER from the request headers
and adds a request_id field to the span; update the layer setup where
TraceLayer::new_for_http() is called alongside PropagateRequestIdLayer::new(...)
so emitted spans contain the request_id for correlation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: bf3cc68e-2f0b-445b-86b5-f2e6f296d93a
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (8)
.env.exampleCargo.tomlsrc/api/health.rssrc/api/mod.rssrc/config.rssrc/lib.rssrc/main.rstests/health.rs
Two valid issues caught on the 1.b.1 review: 1. `Config::from_env` accepted `WAVEFLOW_REQUEST_TIMEOUT_SECS=0`, which would make every request 408 before reaching the handler. Bail at boot with a clear error so the misconfig fails fast. 2. The TraceLayer used `DefaultMakeSpan`, which drops every header — the propagated request id never made it into the access log, so correlation between a 5xx and its trace was impossible. Custom `make_span_with` extracts just the `x-request-id` header (not `include_headers(true)`, which would leak Authorization / Cookie into the log sinks). Signed-off-by: InstaZDLL <github.105mh@8shield.net>
Summary
First brick of RFC-001 Phase 1.b. Sets up the axum runtime so the next PRs (1.b.2 Postgres + migrations, 1.b.3 OpenAPI via utoipa, 1.b.4 CRUD modules) land on a stable foundation.
What's wired
The API surface is just `GET /health` for now — returns `{status, version}` and is the template every future resource module will follow.
Out of scope (intentionally)
Test plan
Signed-off-by: InstaZDLL github.105mh@8shield.net
Summary by CodeRabbit
New Features
Tests
Chores