Skip to content

qmilangowin/rust-service-bootstrap

Repository files navigation

Rust Bootstrap App

Ask DeepWiki

Production-grade Rust microservice skeleton with lifecycle management, observability, and Docker support.

Living document. This bootstrap evolves as better workflows and patterns are discovered. If you spot something that could be improved — a better pattern, a missing skill, a sharper rule — open an MR or leave a comment. Contributions welcome.

Architecture

crates/
├── app/                # Binary crate — CLI, config, bootstrap wiring
│   └── src/
│       ├── main.rs         # Thin entrypoint: parse CLI → bootstrap → run
│       ├── lib.rs          # Bootstrap: health + metrics + tracing wiring
│       └── metrics.rs      # Prometheus metrics, system & tokio collectors
├── app-core/           # Library crate — lifecycle framework
│   └── src/
│       ├── lib.rs          # AppManager trait, RunningStatus, SubsystemHandle re-export
│       ├── manager.rs      # App orchestrator (tokio-graceful-shutdown backend)
│       └── health.rs       # Health HTTP endpoint (actix-web)
│
│   The crates below are example domain crates. Rename them to match your
│   service (e.g. replace "example" with "reporter", "ingestor", etc.).
│
├── example-config/     # Domain config structs (AppConfig, HealthConfig, …)
├── example-core/       # Domain error types and shared primitives
├── example-store/      # Storage trait + mockall feature-gate pattern
└── example-service/    # Domain logic wired to the store via trait abstraction

Features

  • Lifecycle managementAppManager trait backed by tokio-graceful-shutdown, subsystems as async functions
  • Health endpoint — actix-web on :8080/health, backed by RunningStatus (200 when ready, 503 otherwise)
  • Prometheus metrics — actix-web on :9090/metrics, using metrics crate + metrics-exporter-prometheus
  • System metrics — CPU and memory gauges via sysinfo
  • Tokio runtime metrics — workers, parks, steals, polls, busy duration, queue depths via tokio-metrics
  • OpenTelemetry tracing — optional OTLP/gRPC export via opentelemetry-otlp + tonic
  • Structured loggingtracing-subscriber with env-filter, optional JSON output
  • CLIclap with flags for ports, log level, OTel toggle, OTLP endpoint
  • Signal handling — SIGINT/SIGTERM handled automatically by Toplevel::catch_signals()
  • Production lints — 11 clippy lints + unsafe_code = "deny"
  • Pre-commit hooks — fmt + clippy on push

Quick Start

# Install pre-commit (once, if not already installed)
brew install pre-commit   # macOS
# pip install pre-commit  # alternative via pip

# Install pre-commit hooks into this repo
just pre-commit-install

# Build
just build

# Run locally
just run

# Check health & metrics
just health
just metrics

# Run CI checks locally
just ci

Ports

Port Purpose
8080 Health check endpoint (/health)
9090 Prometheus metrics (/metrics)

Endpoints

GET /health (port 8080)

Returns 200 OK when the service is ready, 503 Service Unavailable otherwise.

curl http://localhost:8080/health
# OK

GET /metrics (port 9090)

Prometheus exposition format. Includes system and Tokio runtime metrics:

curl http://localhost:9090/metrics
Metric Description
system_cpu_usage_percent Overall CPU usage
system_memory_used_bytes Physical memory in use
system_memory_total_bytes Total physical memory
tokio_workers_count Number of worker threads
tokio_total_busy_duration_seconds Time workers spent executing tasks
tokio_total_polls_count Total task polls across workers
tokio_total_park_count Times worker threads parked
tokio_total_steal_count Tasks stolen between workers
tokio_global_queue_depth Tasks in the global queue
tokio_total_local_queue_depth Tasks in all worker local queues
tokio_blocking_queue_depth Tasks in the blocking pool queue
tokio_budget_forced_yield_count Forced yields due to budget

These metrics can be scraped by Prometheus and visualized in Grafana.

Docker

# Build image
just docker-build

# Start local stack (app + config)
just stack-up

# View logs
just stack-logs

# Stop and clean up
just stack-reset

AI Workflows

This bootstrap includes ready-to-use AI context for both Cursor and Claude Code. Everything is self-contained — no global config required.

Cursor

.cursor/rules/project.mdc is automatically loaded when you open the project. It includes working-style rules, code style conventions, and project context.

Update the Project Context and Project-Specific Rules sections to reflect your service after renaming the example-* crates.

Claude Code

CLAUDE.md at the repo root is automatically loaded by Claude Code. Same content as the Cursor rule — working-style, QA, code style, and project context.

Three skills are available in .claude/skills/rust/:

Skill Trigger keywords Purpose
cargo-check "check rust", "cargo check", "run clippy", "before commit" Run check + clippy + tests + fmt
add-dependency "add crate", "add dependency", "cargo add" Add crate with version lookup and features
fix-error "fix error", "rust error", "compiler error" Analyze and fix Rust compiler errors

If you maintain a global ~/.claude/CLAUDE.md, you can slim down the project CLAUDE.md to just the Project Context and Project-Specific Rules sections, replacing the working-style content with @~/.claude/CLAUDE.md.

Extending for a specific domain

The rules in CLAUDE.md and project.mdc are intentionally generic. For domain-specific work, add a section to the Project-Specific Rules block that layers constraints on top of the generic ones.

For example, a financial service might add:

## Domain Rules — Finance

# Nick Leeson bankrupted a 233-year-old bank because nobody asked obvious questions.
# These rules exist so we have to ask them.

**Canonical crates**: Use [`rust_decimal`](https://crates.io/crates/rust_decimal)
for all monetary and decimal values — never `f32`/`f64`. Use
[`chrono`](https://crates.io/crates/chrono) for dates and times with explicit
timezone handling.

**Units and precision**: Never assume units (basis points, dollars, cents, percent).
Never assume decimal precision. Always confirm before implementing any numeric
type or calculation.

**No silent rounding**: Any rounding, truncation, or precision loss must be
explicit and confirmed. Flag it as a decision point, not an implementation detail.

**Audit trail**: Any function that mutates state or touches external systems
(DB, API, queue) must be discussed before writing. Consider whether it needs
logging or an audit record.

**Assumptions**: The bar for silent assumptions is zero.
If it touches money, positions, risk, or counterparties — ask.
If it compiles but feels wrong — ask.
If you're about to write a comment saying "this should be fine" — ask.

The same pattern applies to any domain — canonical crates, invariants, and constraints that are specific to your context.

Toolchain

Tool Version
Rust 1.85 (pinned via rust-toolchain.toml)
Edition 2024
Runtime tokio (multi-thread, tokio_unstable enabled)

Available Commands

Run just to see all available recipes.

About

Production-grade Rust microservice skeleton — lifecycle, observability, graceful shutdown, and AI workflows out of the box.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors