use ipfrs::{
health::{HealthChecker, HealthStatus},
metrics::{self, MetricsRegistry},
recovery::{retry_async, CircuitBreaker, RetryPolicy},
shutdown::{wait_for_signal, ShutdownCoordinator},
tracing_setup::{init_tracing, TracingConfig},
Block, Constant, Node, NodeConfig, Predicate, Rule, Term,
};
use std::path::PathBuf;
use std::time::Duration;
use tracing::{error, info, info_span, warn};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🚀 Starting Production IPFRS Node...\n");
println!("📊 Setting up observability...");
let tracing_config = TracingConfig::new("ipfrs-production-example".to_string())
.with_log_level("info".to_string());
let _tracing_guard = init_tracing(tracing_config)?;
info!("Distributed tracing initialized");
let metrics_registry = MetricsRegistry::new();
let metrics_addr = "127.0.0.1:9000".parse()?;
metrics_registry.init_prometheus(metrics_addr)?;
info!(
"Prometheus metrics available at http://{}/metrics",
metrics_addr
);
let health_checker = HealthChecker::new();
info!("Health checks initialized");
let shutdown = ShutdownCoordinator::new(Duration::from_secs(30));
info!("Shutdown coordinator initialized");
println!("\n📦 Starting IPFRS node...");
let mut config = NodeConfig::default();
config.storage.path = PathBuf::from("/tmp/ipfrs-production-example");
config.enable_semantic = true;
config.enable_tensorlogic = true;
let mut node = Node::new(config)?;
node.start().await?;
info!("IPFRS node started successfully");
let health_shutdown = shutdown.clone();
tokio::spawn(async move {
health_check_loop(health_checker, health_shutdown).await;
});
let metrics_shutdown = shutdown.clone();
tokio::spawn(async move {
metrics_update_loop(metrics_registry, metrics_shutdown).await;
});
println!("\n✅ Production node is running!");
println!(" - Metrics: http://localhost:9000/metrics");
println!(" - Demonstrating features...\n");
let demo_shutdown = shutdown.clone();
let mut demo_shutdown_rx = demo_shutdown.subscribe();
tokio::select! {
result = demonstrate_features(&mut node) => {
if let Err(e) = result {
error!("Error in demonstration: {}", e);
} else {
info!("✨ All demonstrations completed successfully");
}
}
_ = demo_shutdown_rx.recv() => {
info!("Shutdown requested during demonstration");
}
}
println!("\n📊 System is operational. Press Ctrl+C to shutdown gracefully\n");
let signal = wait_for_signal().await;
info!("Received shutdown signal: {:?}", signal);
node.stop().await?;
shutdown.shutdown(signal);
match shutdown.wait_for_shutdown().await {
Ok(()) => info!("Graceful shutdown completed successfully"),
Err(()) => warn!("Graceful shutdown timed out"),
}
println!("\n👋 Production node stopped\n");
Ok(())
}
async fn demonstrate_features(node: &mut Node) -> Result<(), Box<dyn std::error::Error>> {
info!("🎯 Demonstrating production features...");
demonstrate_block_ops_with_retry(node).await?;
demonstrate_semantic_with_circuit_breaker(node).await?;
demonstrate_logic_with_error_handling(node).await?;
Ok(())
}
async fn demonstrate_block_ops_with_retry(
node: &mut Node,
) -> Result<(), Box<dyn std::error::Error>> {
let span = info_span!("block_operations");
let _guard = span.enter();
info!("📦 Block Operations with Retry");
let retry_policy = RetryPolicy::exponential(3, Duration::from_millis(100));
for i in 0..5 {
let data = format!("Production Block {}", i);
let data_len = data.len();
let start = std::time::Instant::now();
let data_clone = data.clone();
let cid = retry_async(retry_policy.clone(), || {
let data_inner = data_clone.clone();
async move {
let block = Block::new(data_inner.into_bytes().into())
.map_err(|e| format!("Block creation error: {}", e))?;
let cid = *block.cid();
Ok::<_, String>(cid)
}
})
.await?;
let block = Block::new(data.into_bytes().into())?;
node.put_block(&block).await?;
let duration_ms = start.elapsed().as_secs_f64() * 1000.0;
metrics::record_block_put(data_len, duration_ms);
info!(" ✓ Stored block {}: {} ({:.2}ms)", i, cid, duration_ms);
}
let stats = node.storage_stats()?;
metrics::set_block_count(stats.num_blocks);
metrics::set_storage_size_bytes(0);
info!(" 📊 Storage: {} blocks", stats.num_blocks);
Ok(())
}
async fn demonstrate_semantic_with_circuit_breaker(
node: &mut Node,
) -> Result<(), Box<dyn std::error::Error>> {
let span = info_span!("semantic_search");
let _guard = span.enter();
info!("🔍 Semantic Search with Circuit Breaker");
let breaker = CircuitBreaker::new(5, 2, Duration::from_secs(60));
for i in 0..10 {
let data = format!("Document {}: AI and machine learning content", i);
let block = Block::new(data.into_bytes().into())?;
let cid = *block.cid();
node.put_block(&block).await?;
let embedding: Vec<f32> = (0..768).map(|j| ((i + j) as f32) / 100.0).collect();
let start = std::time::Instant::now();
node.index_content(&cid, &embedding).await?;
let duration_ms = start.elapsed().as_secs_f64() * 1000.0;
metrics::record_vector_index(768, duration_ms);
}
let query: Vec<f32> = (0..768).map(|i| i as f32 / 100.0).collect();
let start = std::time::Instant::now();
let results = if breaker.is_available() {
match node.search_similar(&query, 5).await {
Ok(results) => {
breaker.record_success();
results
}
Err(e) => {
breaker.record_failure();
return Err(format!("Search error: {}", e).into());
}
}
} else {
return Err("Circuit breaker is open, search unavailable".into());
};
let duration_ms = start.elapsed().as_secs_f64() * 1000.0;
metrics::record_similarity_search(5, results.len(), duration_ms);
info!(
" ✓ Found {} similar items ({:.2}ms)",
results.len(),
duration_ms
);
let stats = node.semantic_stats()?;
metrics::set_vector_count(stats.num_vectors);
info!(
" 📊 Vectors: {}, Dimension: {}",
stats.num_vectors, stats.dimension
);
Ok(())
}
async fn demonstrate_logic_with_error_handling(
node: &mut Node,
) -> Result<(), Box<dyn std::error::Error>> {
let span = info_span!("logic_programming");
let _guard = span.enter();
info!("🧠 Logic Programming with Error Handling");
let facts = vec![("Alice", "Bob"), ("Bob", "Charlie"), ("Charlie", "Diana")];
for (parent, child) in &facts {
let fact = Predicate::new(
"parent".to_string(),
vec![
Term::Const(Constant::String(parent.to_string())),
Term::Const(Constant::String(child.to_string())),
],
);
let start = std::time::Instant::now();
node.add_fact(fact)?;
let duration_ms = start.elapsed().as_secs_f64() * 1000.0;
metrics::record_fact_add(duration_ms);
}
let rule = Rule::new(
Predicate::new(
"grandparent".to_string(),
vec![Term::Var("X".to_string()), Term::Var("Z".to_string())],
),
vec![
Predicate::new(
"parent".to_string(),
vec![Term::Var("X".to_string()), Term::Var("Y".to_string())],
),
Predicate::new(
"parent".to_string(),
vec![Term::Var("Y".to_string()), Term::Var("Z".to_string())],
),
],
);
let start = std::time::Instant::now();
node.add_rule(rule)?;
let duration_ms = start.elapsed().as_secs_f64() * 1000.0;
metrics::record_rule_add(duration_ms);
let goal = Predicate::new(
"grandparent".to_string(),
vec![
Term::Var("X".to_string()),
Term::Const(Constant::String("Charlie".to_string())),
],
);
let start = std::time::Instant::now();
let results = node.infer(&goal)?;
let duration_ms = start.elapsed().as_secs_f64() * 1000.0;
metrics::record_inference(results.len(), duration_ms);
info!(
" ✓ Inference found {} results ({:.2}ms)",
results.len(),
duration_ms
);
let stats = node.tensorlogic_stats()?;
metrics::set_kb_stats(stats.num_facts, stats.num_rules);
info!(
" 📊 Knowledge Base: {} facts, {} rules",
stats.num_facts, stats.num_rules
);
Ok(())
}
async fn health_check_loop(checker: HealthChecker, shutdown: ShutdownCoordinator) {
let mut interval = tokio::time::interval(Duration::from_secs(10));
let mut shutdown_rx = shutdown.subscribe();
loop {
tokio::select! {
_ = interval.tick() => {
let health = checker.check_readiness(true, true, true, true);
match health.status {
HealthStatus::Healthy => {
info!("❤️ Health check: HEALTHY (uptime: {}s)", health.uptime_seconds);
}
HealthStatus::Degraded => {
warn!("⚠️ Health check: DEGRADED (uptime: {}s)", health.uptime_seconds);
}
HealthStatus::Unhealthy => {
error!("❌ Health check: UNHEALTHY (uptime: {}s)", health.uptime_seconds);
}
}
}
_ = shutdown_rx.recv() => {
info!("Health check loop shutting down");
break;
}
}
}
}
async fn metrics_update_loop(registry: MetricsRegistry, shutdown: ShutdownCoordinator) {
let mut interval = tokio::time::interval(Duration::from_secs(5));
let mut shutdown_rx = shutdown.subscribe();
loop {
tokio::select! {
_ = interval.tick() => {
let uptime = registry.uptime_seconds();
metrics::set_uptime_seconds(uptime);
}
_ = shutdown_rx.recv() => {
info!("Metrics update loop shutting down");
break;
}
}
}
}