1#![allow(clippy::disallowed_types)] use std::collections::HashMap;
5use std::path::PathBuf;
6
7use laminar_connectors::connector::DeliveryGuarantee;
8use laminar_core::streaming::{BackpressureStrategy, StreamCheckpointConfig};
9
10pub const DEFAULT_MAX_MANAGED_STATE_BYTES: usize = 256 * 1024 * 1024;
14
15pub(crate) fn event_time_max_future_skew_ms(
16 skew: std::time::Duration,
17) -> Result<i64, &'static str> {
18 let skew_ms = i64::try_from(skew.as_millis())
19 .map_err(|_| "event_time_max_future_skew exceeds the supported millisecond range")?;
20 if !skew.is_zero() && skew_ms == 0 {
21 return Err("event_time_max_future_skew must be zero or at least 1ms");
22 }
23 Ok(skew_ms)
24}
25
26pub(crate) fn source_idle_timeout_ms(
27 timeout: Option<std::time::Duration>,
28) -> Result<Option<u64>, &'static str> {
29 let Some(timeout) = timeout else {
30 return Ok(None);
31 };
32 let timeout_ms = u64::try_from(timeout.as_millis())
33 .map_err(|_| "source_idle_timeout exceeds the supported millisecond range")?;
34 if timeout_ms == 0 {
35 return Err("source_idle_timeout must be at least 1ms");
36 }
37 Ok(Some(timeout_ms))
38}
39
40pub(crate) fn temporal_join_idle_history_retention_ms(
41 retention: Option<std::time::Duration>,
42) -> Result<i64, &'static str> {
43 let retention = retention
44 .ok_or("temporal_join_idle_history_retention must be configured for temporal joins")?;
45 let retention_ms = i64::try_from(retention.as_millis()).map_err(|_| {
46 "temporal_join_idle_history_retention exceeds the supported millisecond range"
47 })?;
48 if retention_ms == 0 {
49 return Err("temporal_join_idle_history_retention must be at least 1ms");
50 }
51 Ok(retention_ms)
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
56pub enum BackpressurePolicy {
57 #[default]
59 Backpressure,
60 ShedOldest,
62 Fail,
64}
65
66#[derive(Clone)]
68pub struct SecretString(String);
69
70impl SecretString {
71 pub fn new(value: impl Into<String>) -> Self {
73 Self(value.into())
74 }
75
76 #[must_use]
78 pub fn expose(&self) -> &str {
79 &self.0
80 }
81}
82
83impl std::fmt::Debug for SecretString {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 f.write_str("\"[REDACTED]\"")
86 }
87}
88
89#[derive(Debug, Clone)]
91pub struct RestartPolicy {
92 pub max_restarts: usize,
94 pub window: std::time::Duration,
96 pub initial_backoff: std::time::Duration,
98 pub max_backoff: std::time::Duration,
100}
101
102impl Default for RestartPolicy {
103 fn default() -> Self {
104 Self {
105 max_restarts: 5,
106 window: std::time::Duration::from_secs(60),
107 initial_backoff: std::time::Duration::from_millis(500),
108 max_backoff: std::time::Duration::from_secs(30),
109 }
110 }
111}
112
113#[derive(Debug, Clone)]
115pub struct LaminarConfig {
116 pub default_buffer_size: usize,
118 pub default_backpressure: BackpressureStrategy,
120 pub storage_dir: Option<PathBuf>,
122 pub checkpoint: Option<StreamCheckpointConfig>,
124 pub incremental_emit: bool,
127 pub object_store_url: Option<String>,
129 pub object_store_options: HashMap<String, String>,
131 pub http_auth_token: Option<SecretString>,
134 pub delivery_guarantee: DeliveryGuarantee,
136 pub pipeline_channel_capacity: Option<usize>,
138 pub pipeline_batch_window: Option<std::time::Duration>,
140 pub pipeline_drain_budget_ns: Option<u64>,
142 pub pipeline_query_budget_ns: Option<u64>,
144 pub pipeline_max_input_buf_batches: Option<usize>,
146 pub pipeline_max_input_buf_bytes: Option<usize>,
148 pub pipeline_max_managed_state_bytes: Option<usize>,
151 pub temporal_join_idle_history_retention: Option<std::time::Duration>,
154 pub source_idle_timeout: Option<std::time::Duration>,
157 pub event_time_max_future_skew: std::time::Duration,
160 pub pipeline_backpressure_policy: BackpressurePolicy,
162 pub restart_policy: RestartPolicy,
164 pub shared_source_isolation: bool,
167}
168
169impl Default for LaminarConfig {
170 fn default() -> Self {
171 Self {
172 default_buffer_size: 65536,
173 default_backpressure: BackpressureStrategy::Block,
174 storage_dir: None,
175 checkpoint: None,
176 incremental_emit: true,
177 object_store_url: None,
178 object_store_options: HashMap::new(),
179 http_auth_token: None,
180 delivery_guarantee: DeliveryGuarantee::default(),
181 pipeline_channel_capacity: None,
182 pipeline_batch_window: None,
183 pipeline_drain_budget_ns: None,
184 pipeline_query_budget_ns: None,
185 pipeline_max_input_buf_batches: None,
186 pipeline_max_input_buf_bytes: None,
187 pipeline_max_managed_state_bytes: None,
188 temporal_join_idle_history_retention: None,
189 source_idle_timeout: None,
190 event_time_max_future_skew: std::time::Duration::from_millis(
191 laminar_core::time::DEFAULT_MAX_FUTURE_SKEW_MS.unsigned_abs(),
192 ),
193 pipeline_backpressure_policy: BackpressurePolicy::default(),
194 restart_policy: RestartPolicy::default(),
195 shared_source_isolation: false,
196 }
197 }
198}