use crate::core::net::ProviderEndpointAccess;
use crate::core::providers::Provider;
use crate::utils::auth::crypto::hmac::CredentialDigest;
use parking_lot::RwLock;
use std::fmt;
use std::ops::Deref;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicU8, AtomicU32, AtomicU64, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};
#[path = "deployment/probe_state.rs"]
mod probe_state;
#[path = "deployment/provider_instance.rs"]
mod provider_instance;
use probe_state::ProbeLifecycle;
pub(crate) use probe_state::publish_probe_group;
pub(crate) use provider_instance::ProviderInstanceIdentity;
use url::Url;
pub type DeploymentId = String;
#[derive(Clone)]
pub(crate) struct LegacySelectorMetadata {
credential_digest: CredentialDigest,
}
impl LegacySelectorMetadata {
pub(crate) fn from_stored_credential(credential: &str) -> Self {
Self {
credential_digest: CredentialDigest::from_credential(credential),
}
}
pub(crate) fn credential_matches(&self, request_digest: &CredentialDigest) -> bool {
self.credential_digest.constant_time_matches(request_digest)
}
}
impl fmt::Debug for LegacySelectorMetadata {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("LegacySelectorMetadata")
.field("credential_digest", &"[REDACTED]")
.finish()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct RetrySchedule {
pub base_delay_ms: u64,
pub max_delay_ms: u64,
pub backoff_multiplier: f64,
pub jitter_ratio: f64,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct HealthCheckPolicy {
pub provider_name: String,
pub interval_secs: u64,
pub failure_threshold: u32,
pub recovery_timeout_secs: u64,
pub endpoint: Option<Url>,
pub endpoint_access: ProviderEndpointAccess,
pub expected_codes: Vec<u16>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum HealthStatus {
Unknown = 0,
Healthy = 1,
Degraded = 2,
Unhealthy = 3,
Cooldown = 4,
}
impl From<u8> for HealthStatus {
fn from(value: u8) -> Self {
match value {
1 => HealthStatus::Healthy,
2 => HealthStatus::Degraded,
3 => HealthStatus::Unhealthy,
4 => HealthStatus::Cooldown,
_ => HealthStatus::Unknown,
}
}
}
impl From<HealthStatus> for u8 {
fn from(status: HealthStatus) -> Self {
status as u8
}
}
#[derive(Debug, Clone)]
pub struct DeploymentConfig {
pub tpm_limit: Option<u64>,
pub rpm_limit: Option<u64>,
pub max_parallel_requests: Option<u32>,
pub weight: u32,
pub timeout_secs: u64,
pub priority: u32,
pub retry_schedule: Option<RetrySchedule>,
pub health_check_policy: Option<HealthCheckPolicy>,
}
impl Default for DeploymentConfig {
fn default() -> Self {
Self {
tpm_limit: None,
rpm_limit: None,
max_parallel_requests: None,
weight: 1,
timeout_secs: 60,
priority: 0,
retry_schedule: None,
health_check_policy: None,
}
}
}
#[derive(Debug, Clone)]
pub struct DeploymentState {
inner: Arc<DeploymentStateInner>,
minute_window_lock: Arc<RwLock<()>>,
provider_instance_identity: ProviderInstanceIdentity,
probe_health: Arc<AtomicU8>,
probe_last_checked_at_millis: Arc<AtomicU64>,
probe_lifecycle: Arc<ProbeLifecycle>,
probe_generation: u64,
}
impl Deref for DeploymentState {
type Target = DeploymentStateInner;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[derive(Debug)]
pub struct DeploymentStateInner {
pub health: AtomicU8,
pub probe_unhealthy: AtomicBool,
pub tpm_current: AtomicU64,
pub rpm_current: AtomicU64,
pub active_requests: AtomicU32,
pub total_requests: AtomicU64,
pub success_requests: AtomicU64,
pub fail_requests: AtomicU64,
pub fails_this_minute: AtomicU32,
pub cooldown_until: AtomicU64,
pub last_request_at: AtomicU64,
pub avg_latency_us: AtomicU64,
pub consecutive_successes: AtomicU32,
pub minute_reset_at: AtomicU64,
}
impl DeploymentState {
pub fn new() -> Self {
Self::new_for_provider_instance(ProviderInstanceIdentity::new())
}
fn new_for_provider_instance(provider_instance_identity: ProviderInstanceIdentity) -> Self {
let now = current_timestamp();
Self {
inner: Arc::new(DeploymentStateInner {
health: AtomicU8::new(HealthStatus::Healthy as u8),
probe_unhealthy: AtomicBool::new(false),
tpm_current: AtomicU64::new(0),
rpm_current: AtomicU64::new(0),
active_requests: AtomicU32::new(0),
total_requests: AtomicU64::new(0),
success_requests: AtomicU64::new(0),
fail_requests: AtomicU64::new(0),
fails_this_minute: AtomicU32::new(0),
cooldown_until: AtomicU64::new(0),
last_request_at: AtomicU64::new(0),
avg_latency_us: AtomicU64::new(0),
consecutive_successes: AtomicU32::new(0),
minute_reset_at: AtomicU64::new(now),
}),
minute_window_lock: Arc::new(RwLock::new(())),
provider_instance_identity,
probe_health: Arc::new(AtomicU8::new(HealthStatus::Unknown as u8)),
probe_last_checked_at_millis: Arc::new(AtomicU64::new(0)),
probe_lifecycle: Arc::new(ProbeLifecycle::new()),
probe_generation: 0,
}
}
pub fn reset_minute(&self) {
let _guard = self.minute_window_lock.write();
self.finish_minute_reset(current_timestamp());
}
pub(crate) fn roll_minute_window(&self, now: u64) {
self.with_current_minute(now, || ());
}
pub(crate) fn minute_counters(&self, now: u64) -> MinuteCounters {
self.roll_minute_window(now);
let _guard = self.minute_window_lock.read();
MinuteCounters {
tpm: self.tpm_current.load(Ordering::Relaxed),
rpm: self.rpm_current.load(Ordering::Relaxed),
failures: self.fails_this_minute.load(Ordering::Relaxed),
}
}
fn with_current_minute<T>(&self, now: u64, operation: impl FnOnce() -> T) -> T {
let guard = self.minute_window_lock.read();
let last = self.minute_reset_at.load(Ordering::Acquire);
if !minute_window_needs_roll(now, last) {
let result = operation();
drop(guard);
return result;
}
drop(guard);
let reset_guard = self.minute_window_lock.write();
let reset_now = current_timestamp();
let last = self.minute_reset_at.load(Ordering::Acquire);
if minute_window_needs_roll(reset_now, last) {
self.finish_minute_reset(reset_now);
}
let result = operation();
drop(reset_guard);
result
}
fn finish_minute_reset(&self, now: u64) {
self.tpm_current.store(0, Ordering::Relaxed);
self.rpm_current.store(0, Ordering::Relaxed);
self.fails_this_minute.store(0, Ordering::Relaxed);
self.minute_reset_at.store(now, Ordering::Release);
}
pub fn health_status(&self) -> HealthStatus {
self.health.load(Ordering::Relaxed).into()
}
pub fn probe_health_status(&self) -> HealthStatus {
self.probe_health.load(Ordering::Acquire).into()
}
pub(crate) fn set_probe_health_status(&self, status: HealthStatus) {
self.probe_last_checked_at_millis
.store(current_timestamp_millis(), Ordering::Relaxed);
self.probe_health.store(status as u8, Ordering::Release);
}
pub fn probe_last_checked_at_millis(&self) -> Option<u64> {
match self.probe_last_checked_at_millis.load(Ordering::Relaxed) {
0 => None,
timestamp => Some(timestamp),
}
}
pub(crate) fn for_snapshot_insertion(&self) -> Self {
self.for_snapshot_insertion_with_provider(self.provider_instance_identity.clone())
}
pub(crate) fn for_snapshot_insertion_with_provider(
&self,
provider_instance_identity: ProviderInstanceIdentity,
) -> Self {
let probe_generation = self.probe_lifecycle.next_generation();
Self {
inner: Arc::clone(&self.inner),
minute_window_lock: Arc::clone(&self.minute_window_lock),
provider_instance_identity,
probe_health: Arc::new(AtomicU8::new(HealthStatus::Unknown as u8)),
probe_last_checked_at_millis: Arc::new(AtomicU64::new(0)),
probe_lifecycle: Arc::clone(&self.probe_lifecycle),
probe_generation,
}
}
pub(crate) fn provider_instance_identity(&self) -> ProviderInstanceIdentity {
self.provider_instance_identity.clone()
}
}
impl Default for DeploymentState {
fn default() -> Self {
Self::new()
}
}
const MINUTE_WINDOW_SECS: u64 = 60;
fn minute_window_needs_roll(now: u64, last: u64) -> bool {
now < last || now - last >= MINUTE_WINDOW_SECS
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct MinuteCounters {
pub(crate) tpm: u64,
pub(crate) rpm: u64,
pub(crate) failures: u32,
}
#[derive(Debug, Clone)]
pub struct Deployment {
pub id: DeploymentId,
pub provider: Provider,
pub model: String,
pub model_name: String,
pub config: DeploymentConfig,
pub state: DeploymentState,
pub tags: Vec<String>,
}
impl Deployment {
pub fn new(id: DeploymentId, provider: Provider, model: String, model_name: String) -> Self {
Self::new_with_provider_instance(
id,
provider,
model,
model_name,
ProviderInstanceIdentity::new(),
)
}
pub(crate) fn new_with_provider_instance(
id: DeploymentId,
provider: Provider,
model: String,
model_name: String,
provider_instance_identity: ProviderInstanceIdentity,
) -> Self {
Self {
id,
provider,
model,
model_name,
config: DeploymentConfig::default(),
state: DeploymentState::new_for_provider_instance(provider_instance_identity),
tags: Vec::new(),
}
}
pub fn with_config(mut self, config: DeploymentConfig) -> Self {
self.config = config;
self
}
pub fn with_tags(mut self, tags: Vec<String>) -> Self {
self.tags = tags;
self
}
pub fn is_healthy(&self) -> bool {
let status = self.state.health_status();
matches!(status, HealthStatus::Healthy | HealthStatus::Degraded)
}
pub fn is_in_cooldown(&self) -> bool {
let cooldown_until = self.state.cooldown_until.load(Ordering::Relaxed);
if cooldown_until == 0 {
return false;
}
let now = current_timestamp();
if cooldown_until > now {
return true;
}
let next = if self.state.probe_unhealthy.load(Ordering::Relaxed) {
HealthStatus::Unhealthy
} else {
HealthStatus::Degraded
};
self.state
.health
.compare_exchange(
HealthStatus::Cooldown as u8,
next as u8,
Ordering::Relaxed,
Ordering::Relaxed,
)
.ok();
false
}
pub fn record_success(&self, tokens: u64, latency_us: u64) {
let now = current_timestamp();
self.state.total_requests.fetch_add(1, Ordering::Relaxed);
self.state.success_requests.fetch_add(1, Ordering::Relaxed);
self.state.with_current_minute(now, || {
self.state.tpm_current.fetch_add(tokens, Ordering::Relaxed);
self.state.rpm_current.fetch_add(1, Ordering::Relaxed);
});
self.state.last_request_at.store(now, Ordering::Relaxed);
let current_avg = self.state.avg_latency_us.load(Ordering::Relaxed);
let new_avg = if current_avg == 0 {
latency_us
} else {
(latency_us + 4 * current_avg) / 5
};
self.state.avg_latency_us.store(new_avg, Ordering::Relaxed);
self.state
.consecutive_successes
.fetch_add(1, Ordering::Relaxed);
}
#[cfg(feature = "gateway")]
pub(crate) fn record_partial_tokens(&self, tokens: u64) {
self.state.with_current_minute(current_timestamp(), || {
self.state.tpm_current.fetch_add(tokens, Ordering::Relaxed);
});
}
#[cfg(feature = "websockets")]
pub(crate) fn record_interrupted_usage(&self, tokens: u64) {
self.state.with_current_minute(current_timestamp(), || {
self.state.tpm_current.fetch_add(tokens, Ordering::Relaxed);
self.state.rpm_current.fetch_add(1, Ordering::Relaxed);
});
}
pub fn record_failure(&self) {
self.record_failure_with_minute_counters();
}
pub(crate) fn record_failure_with_minute_counters(&self) -> MinuteCounters {
let now = current_timestamp();
self.state.total_requests.fetch_add(1, Ordering::Relaxed);
self.state.fail_requests.fetch_add(1, Ordering::Relaxed);
let counters = self.state.with_current_minute(now, || {
self.state.fails_this_minute.fetch_add(1, Ordering::Relaxed);
MinuteCounters {
tpm: self.state.tpm_current.load(Ordering::Relaxed),
rpm: self.state.rpm_current.load(Ordering::Relaxed),
failures: self.state.fails_this_minute.load(Ordering::Relaxed),
}
});
self.state.last_request_at.store(now, Ordering::Relaxed);
self.state.consecutive_successes.store(0, Ordering::Relaxed);
let mut current = self.state.health.load(Ordering::Relaxed);
while matches!(
HealthStatus::from(current),
HealthStatus::Healthy | HealthStatus::Unknown
) {
match self.state.health.compare_exchange_weak(
current,
HealthStatus::Degraded as u8,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => break,
Err(observed) => current = observed,
}
}
counters
}
pub(crate) fn promote_to_healthy_if_degraded(&self) {
let mut current = self.state.health.load(Ordering::Relaxed);
while current == HealthStatus::Degraded as u8 {
match self.state.health.compare_exchange_weak(
current,
HealthStatus::Healthy as u8,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => break,
Err(observed) => current = observed,
}
}
}
pub fn enter_cooldown(&self, duration_secs: u64) {
let cooldown_until = current_timestamp() + duration_secs;
self.state
.cooldown_until
.store(cooldown_until, Ordering::Relaxed);
let mut current = self.state.health.load(Ordering::Relaxed);
while HealthStatus::from(current) != HealthStatus::Cooldown {
match self.state.health.compare_exchange_weak(
current,
HealthStatus::Cooldown as u8,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => break,
Err(observed) => current = observed,
}
}
}
}
pub(crate) fn current_timestamp() -> u64 {
current_timestamp_duration().as_secs()
}
fn current_timestamp_millis() -> u64 {
current_timestamp_duration()
.as_millis()
.try_into()
.unwrap_or(u64::MAX)
}
fn current_timestamp_duration() -> std::time::Duration {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_else(|_| std::time::Duration::from_secs(0))
}
#[cfg(test)]
#[path = "deployment/tests.rs"]
mod tests;
#[cfg(test)]
#[path = "deployment_window_tests.rs"]
mod deployment_window_tests;