- m0p3: CONTRIBUTING.md with run-samples checklist, all 4 examples (quickstart, cli_embedding, axum_embedding, actix_embedding), doc-test coverage for every public API surface - m1p5: TidalDb public API — write_item, signal, read_decay_score, read_windowed_count, read_velocity; StorageBox enum routing memory vs fjall; WalSender/WalHandleWriter bridge; WAL replay on open - Periodic checkpoint: 30s background thread for persistent+schema mode; FjallBackend::Clone (O(1), fjall::Keyspace is ref-counted); graceful shutdown via Arc<AtomicBool> + join before final checkpoint - ROADMAP.md: M0 and M1 fully marked COMPLETE (341 tests passing) - Milestone 2 planning scaffolding added under docs/planning/milestone-2/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
67 lines
2.1 KiB
Rust
67 lines
2.1 KiB
Rust
//! tidalDB + Axum: embedding a tidalDB instance in an Axum web server.
|
|
//!
|
|
//! Demonstrates:
|
|
//! - Wrapping `TidalDb` in `Arc` for shared ownership across handler threads
|
|
//! - Passing the instance via Axum `State<Arc<TidalDb>>`
|
|
//! - A `/health` route that calls `health_check()`
|
|
//! - Graceful shutdown via `tokio::signal::ctrl_c()`
|
|
//!
|
|
//! `TidalDb` is not `Clone`, so it must be wrapped in `Arc` for use with
|
|
//! Axum's `State<T>`, which requires `T: Clone + Send + Sync + 'static`.
|
|
//!
|
|
//! # Running
|
|
//!
|
|
//! ```bash
|
|
//! cargo run --example axum_embedding --manifest-path tidal/Cargo.toml
|
|
//! # Then: curl http://127.0.0.1:3000/health
|
|
//! ```
|
|
|
|
use std::sync::Arc;
|
|
|
|
use axum::{Router, extract::State, routing::get};
|
|
use tidaldb::TidalDb;
|
|
|
|
async fn health(State(db): State<Arc<TidalDb>>) -> &'static str {
|
|
match db.health_check() {
|
|
Ok(()) => "ok",
|
|
Err(_) => "degraded",
|
|
}
|
|
}
|
|
|
|
/// Resolves when Ctrl+C is received.
|
|
async fn shutdown_signal() {
|
|
tokio::signal::ctrl_c()
|
|
.await
|
|
.unwrap_or_else(|e| eprintln!("ctrl-c error: {e}"));
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
tracing_subscriber::fmt()
|
|
.with_env_filter("tidaldb=debug")
|
|
.init();
|
|
|
|
// `TidalDb` is not Clone — wrap in Arc so the router and main both hold a
|
|
// reference. The router clone gets the weak reference; main retains the
|
|
// strong reference for explicit shutdown ordering.
|
|
let db = Arc::new(TidalDb::builder().ephemeral().open()?);
|
|
|
|
let app = Router::new()
|
|
.route("/health", get(health))
|
|
.with_state(Arc::clone(&db));
|
|
|
|
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?;
|
|
let addr = listener.local_addr()?;
|
|
println!("listening on http://{addr}");
|
|
println!(" GET /health -> tidalDB health check");
|
|
println!("press Ctrl+C to stop");
|
|
|
|
axum::serve(listener, app)
|
|
.with_graceful_shutdown(shutdown_signal())
|
|
.await?;
|
|
|
|
// `db` drops here, calling TidalDb::drop() -> shutdown_inner().
|
|
// Future milestones: WAL drain and storage flush happen in close().
|
|
Ok(())
|
|
}
|