| Crates.io | sentinel-common |
| lib.rs | sentinel-common |
| version | 0.4.2 |
| created_at | 2025-12-25 07:46:48.547475+00 |
| updated_at | 2026-01-21 20:00:28.350224+00 |
| description | Common utilities and types for Sentinel reverse proxy |
| homepage | https://github.com/raskell-io/sentinel |
| repository | https://github.com/raskell-io/sentinel |
| max_upload_size | |
| id | 2004318 |
| size | 292,905 |
Shared types, utilities, and infrastructure for all Sentinel components.
The sentinel-common crate provides the foundational building blocks used across the Sentinel platform:
| Module | Description |
|---|---|
ids |
Type-safe identifiers (RouteId, UpstreamId, AgentId) and hierarchical scoping |
types |
Common types (HttpMethod, TlsVersion, LoadBalancingAlgorithm, etc.) |
errors |
Error types with HTTP status mapping and client-safe messages |
limits |
Resource limits and rate limiting infrastructure |
observability |
Prometheus metrics and tracing initialization |
circuit_breaker |
Circuit breaker state machine |
registry |
Generic thread-safe component registry |
scoped_registry |
Scope-aware hierarchical registry |
scoped_metrics |
Namespace/service-scoped metrics |
budget |
Token budgets and cost attribution for inference |
inference |
Inference health check configurations |
use sentinel_common::{
// Identifiers
RouteId, UpstreamId, Scope, QualifiedId, CorrelationId,
// Types
HttpMethod, LoadBalancingAlgorithm, CircuitBreakerConfig,
// Errors
SentinelError, SentinelResult,
// Limits
Limits, RateLimiter,
// Observability
RequestMetrics, init_tracing,
// Patterns
CircuitBreaker, Registry, ScopedRegistry,
};
// Initialize tracing
init_tracing();
// Create metrics collector
let metrics = RequestMetrics::new();
// Use type-safe identifiers
let route_id = RouteId::new("api-v1");
let scope = Scope::Service {
namespace: "production".to_string(),
service: "payments".to_string(),
};
// Resolve names through scope chain
let qualified = QualifiedId::new("backend", scope.clone());
println!("Canonical: {}", qualified.canonical()); // "production:payments:backend"
Detailed documentation is available in the docs/ directory:
Sentinel supports hierarchical configuration with scope-based resolution:
Global
└── Namespace (e.g., "production")
└── Service (e.g., "payments")
Names resolve through the scope chain (most specific wins):
use sentinel_common::{Scope, ScopedRegistry};
let registry: ScopedRegistry<Config> = ScopedRegistry::new();
// Insert at different scopes
registry.insert(QualifiedId::global("timeout"), global_config);
registry.insert(QualifiedId::namespaced("production", "timeout"), prod_config);
registry.insert(QualifiedId::in_service("production", "payments", "timeout"), payments_config);
// Resolve from service scope
let scope = Scope::Service {
namespace: "production".to_string(),
service: "payments".to_string(),
};
// Finds "production:payments:timeout" first
let config = registry.resolve("timeout", &scope);
All errors map to appropriate HTTP status codes:
use sentinel_common::{SentinelError, SentinelResult};
fn process_request() -> SentinelResult<Response> {
// Errors automatically map to HTTP status
Err(SentinelError::RateLimit {
message: "Too many requests".to_string(),
retry_after_secs: Some(60),
})
}
// In handler
match result {
Ok(response) => response,
Err(e) => {
let status = e.to_http_status(); // 429
let message = e.client_message(); // Safe for client
// ...
}
}
Hard bounds prevent resource exhaustion:
use sentinel_common::Limits;
// Production defaults
let limits = Limits::for_production();
// Check before processing
if body.len() > limits.max_body_size_bytes {
return Err(SentinelError::LimitExceeded {
limit_type: LimitType::BodySize,
message: "Request body too large".to_string(),
current_value: body.len() as u64,
limit: limits.max_body_size_bytes as u64,
});
}
Prometheus metrics with automatic registration:
use sentinel_common::RequestMetrics;
let metrics = RequestMetrics::new();
// Record request
metrics.record_request("api", "GET", 200, Duration::from_millis(50));
// Track active requests
metrics.inc_active_requests();
// ... process ...
metrics.dec_active_requests();
// Circuit breaker state
metrics.set_circuit_breaker_state("upstream", "api", true);
Failure isolation with automatic recovery:
use sentinel_common::{CircuitBreaker, CircuitBreakerConfig};
let config = CircuitBreakerConfig {
failure_threshold: 5,
success_threshold: 2,
timeout_seconds: 30,
half_open_max_requests: 1,
};
let breaker = CircuitBreaker::new(config);
// Check before calling
if !breaker.is_closed() {
return Err(SentinelError::CircuitBreakerOpen { ... });
}
// Record result
match upstream_call().await {
Ok(response) => {
breaker.record_success();
Ok(response)
}
Err(e) => {
breaker.record_failure();
Err(e)
}
}
For inference routes with usage limits:
use sentinel_common::{TokenBudgetConfig, BudgetPeriod, BudgetCheckResult};
let config = TokenBudgetConfig {
period: BudgetPeriod::Daily,
limit: 1_000_000,
enforce: true,
alert_thresholds: vec![0.80, 0.90, 0.95],
..Default::default()
};
// Check budget before processing
match budget_tracker.check(estimated_tokens) {
BudgetCheckResult::Allowed { remaining } => {
// Process request
}
BudgetCheckResult::Exhausted { retry_after_secs } => {
return Err(SentinelError::LimitExceeded { ... });
}
BudgetCheckResult::Soft { remaining, over_by } => {
// Allowed via burst allowance
}
}
| Crate | Uses |
|---|---|
config |
Types, Limits, Error handling, ID types |
proxy |
All modules - core runtime infrastructure |
agent-protocol |
Error types, ID types |
Rust 1.92.0 or later (Edition 2021)