use confique::Config;
use rust_config_tree::ConfigSchema;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use crate::{
config::{
audit::AuditConfig,
ipc_security::IpcSecurityConfig,
policy::{
ChildStrategyOverrideConfig, DynamicSupervisorConfig, FailureWindowConfig,
GroupDependencyConfig, GroupStrategyConfig, GroupsConfigSection, MeltdownConfig,
RestartBudgetConfig, SeverityDefaultConfig, SupervisionPipelineConfig,
},
},
spec::{
child_declaration::ChildrenConfigSection,
supervisor::{
BackpressureConfig, EscalationPolicy, RECOMMENDED_CHANNEL_CAPACITY, SupervisionStrategy,
},
},
};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Config, JsonSchema, ConfigSchema)]
pub struct SupervisorConfig {
#[config(default = [])]
#[serde(default)]
pub include: Vec<PathBuf>,
#[config(nested)]
pub supervisor: SupervisorRootConfig,
#[config(nested)]
#[serde(default)]
pub policy: PolicyConfig,
#[config(nested)]
#[serde(default)]
pub shutdown: ShutdownConfig,
#[config(nested)]
#[serde(default)]
pub observability: ObservabilityConfig,
#[config(nested)]
#[serde(default)]
pub audit: AuditConfig,
#[config(nested)]
#[serde(default)]
pub backpressure: BackpressureConfig,
#[config(nested)]
#[serde(default)]
#[schemars(extend("x-tree-split" = true, "x-tree-transparent-array" = true))]
pub groups: GroupsConfigSection,
#[config(default = [])]
#[serde(default)]
pub group_strategies: Vec<GroupStrategyConfig>,
#[config(default = [])]
#[serde(default)]
pub group_dependencies: Vec<GroupDependencyConfig>,
#[config(default = [])]
#[serde(default)]
pub child_strategy_overrides: Vec<ChildStrategyOverrideConfig>,
#[config(default = [])]
#[serde(default)]
pub severity_defaults: Vec<SeverityDefaultConfig>,
pub dashboard: Option<DashboardIpcConfig>,
#[config(nested)]
#[serde(default)]
#[schemars(extend("x-tree-split" = true, "x-tree-transparent-array" = true))]
pub children: ChildrenConfigSection,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Config, JsonSchema)]
pub struct SupervisorRootConfig {
#[config(default = "OneForAll")]
#[serde(default = "default_supervision_strategy")]
pub strategy: SupervisionStrategy,
#[schemars(!default)]
#[serde(default)]
pub escalation_policy: Option<EscalationPolicy>,
#[config(default = 256)]
#[serde(default = "default_channel_capacity")]
pub control_channel_capacity: usize,
#[config(default = 256)]
#[serde(default = "default_channel_capacity")]
pub event_channel_capacity: usize,
#[config(nested)]
#[serde(default)]
pub dynamic_supervisor: DynamicSupervisorConfig,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Config, JsonSchema)]
pub struct PolicyConfig {
#[config(default = 10)]
#[serde(default = "default_child_restart_limit")]
pub child_restart_limit: u32,
#[config(default = 60000)]
#[serde(default = "default_child_restart_window_ms")]
pub child_restart_window_ms: u64,
#[config(default = 30)]
#[serde(default = "default_supervisor_failure_limit")]
pub supervisor_failure_limit: u32,
#[config(default = 60000)]
#[serde(default = "default_supervisor_failure_window_ms")]
pub supervisor_failure_window_ms: u64,
#[config(default = 100)]
#[serde(default = "default_initial_backoff_ms")]
pub initial_backoff_ms: u64,
#[config(default = 5000)]
#[serde(default = "default_max_backoff_ms")]
pub max_backoff_ms: u64,
#[config(default = 0.10)]
#[serde(default = "default_jitter_ratio")]
pub jitter_ratio: f64,
#[config(default = 1000)]
#[serde(default = "default_heartbeat_interval_ms")]
pub heartbeat_interval_ms: u64,
#[config(default = 3000)]
#[serde(default = "default_stale_after_ms")]
pub stale_after_ms: u64,
#[config(nested)]
#[serde(default)]
pub restart_budget: RestartBudgetConfig,
#[config(nested)]
#[serde(default)]
pub failure_window: FailureWindowConfig,
#[config(nested)]
#[serde(default)]
pub meltdown: MeltdownConfig,
#[config(nested)]
#[serde(default)]
pub supervision_pipeline: SupervisionPipelineConfig,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Config, JsonSchema)]
pub struct ShutdownConfig {
#[config(default = 5000)]
#[serde(default = "default_graceful_timeout_ms")]
pub graceful_timeout_ms: u64,
#[config(default = 1000)]
#[serde(default = "default_abort_wait_ms")]
pub abort_wait_ms: u64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Config, JsonSchema)]
pub struct ObservabilityConfig {
#[config(default = 256)]
#[serde(default = "default_event_journal_capacity")]
pub event_journal_capacity: usize,
#[config(default = true)]
#[serde(default = "default_true")]
pub metrics_enabled: bool,
#[config(default = true)]
#[serde(default = "default_true")]
pub audit_enabled: bool,
}
impl Default for PolicyConfig {
fn default() -> Self {
Self {
child_restart_limit: default_child_restart_limit(),
child_restart_window_ms: default_child_restart_window_ms(),
supervisor_failure_limit: default_supervisor_failure_limit(),
supervisor_failure_window_ms: default_supervisor_failure_window_ms(),
initial_backoff_ms: default_initial_backoff_ms(),
max_backoff_ms: default_max_backoff_ms(),
jitter_ratio: default_jitter_ratio(),
heartbeat_interval_ms: default_heartbeat_interval_ms(),
stale_after_ms: default_stale_after_ms(),
restart_budget: RestartBudgetConfig::default(),
failure_window: FailureWindowConfig::default(),
meltdown: MeltdownConfig::default(),
supervision_pipeline: SupervisionPipelineConfig::default(),
}
}
}
impl Default for ShutdownConfig {
fn default() -> Self {
Self {
graceful_timeout_ms: default_graceful_timeout_ms(),
abort_wait_ms: default_abort_wait_ms(),
}
}
}
impl Default for ObservabilityConfig {
fn default() -> Self {
Self {
event_journal_capacity: default_event_journal_capacity(),
metrics_enabled: default_true(),
audit_enabled: default_true(),
}
}
}
fn default_supervision_strategy() -> SupervisionStrategy {
SupervisionStrategy::OneForAll
}
fn default_child_restart_limit() -> u32 {
10
}
fn default_child_restart_window_ms() -> u64 {
60000
}
fn default_supervisor_failure_limit() -> u32 {
30
}
fn default_supervisor_failure_window_ms() -> u64 {
60000
}
fn default_initial_backoff_ms() -> u64 {
100
}
fn default_max_backoff_ms() -> u64 {
5000
}
fn default_jitter_ratio() -> f64 {
0.10
}
fn default_heartbeat_interval_ms() -> u64 {
1000
}
fn default_stale_after_ms() -> u64 {
3000
}
fn default_graceful_timeout_ms() -> u64 {
5000
}
fn default_abort_wait_ms() -> u64 {
1000
}
fn default_channel_capacity() -> usize {
RECOMMENDED_CHANNEL_CAPACITY
}
fn default_event_journal_capacity() -> usize {
256
}
fn default_true() -> bool {
true
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Config, JsonSchema)]
pub struct DashboardIpcConfig {
pub enabled: bool,
pub target_id: Option<String>,
pub path: Option<PathBuf>,
pub permissions: Option<String>,
pub bind_mode: Option<DashboardIpcBindMode>,
pub registration: Option<DashboardRegistrationConfig>,
#[schemars(!default)]
#[serde(default)]
pub security_config: Option<IpcSecurityConfig>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum DashboardIpcBindMode {
CreateNew,
ReplaceStale,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Config, JsonSchema)]
pub struct DashboardRegistrationConfig {
pub enabled: bool,
pub relay_registration_path: Option<PathBuf>,
pub display_name: Option<String>,
pub lease_seconds: Option<u64>,
pub registration_heartbeat_interval_seconds: Option<u64>,
pub registration_connect_timeout_secs: Option<u64>,
pub registration_io_timeout_secs: Option<u64>,
}