66//!
77//! ## Environment variables
88//!
9- //! | Variable | Description | Default |
10- //! |-------------------------|----------------------------------------------|---------|
11- //! | `NODEDB_LITE_MEMORY_MB` | Total memory budget in mebibytes | 100 |
9+ //! | Variable | Description | Default |
10+ //! |-------------------------------|----------------------------------------------------|---------|
11+ //! | `NODEDB_LITE_MEMORY_MB` | Total memory budget in mebibytes | 100 |
12+ //! | `NODEDB_LITE_AUTO_FLUSH_MS` | Auto-flush interval in milliseconds (0 = disabled) | 1000 |
13+ //! | `NODEDB_LITE_OUTBOUND_QUEUE_CAP` | Max pending entries per durable outbound queue | 100000 |
1214
1315use nodedb_types:: error:: { NodeDbError , NodeDbResult } ;
1416use serde:: { Deserialize , Serialize } ;
@@ -81,12 +83,47 @@ pub struct LiteConfig {
8183 /// A value of 0 is rejected at open time; use 1 as the effective minimum.
8284 #[ serde( default = "default_kv_cache_capacity" ) ]
8385 pub kv_cache_capacity : usize ,
86+
87+ /// Maximum number of pending entries in each durable outbound queue
88+ /// (columnar and timeseries). Default: 100_000.
89+ ///
90+ /// When a queue reaches this cap, write operations return
91+ /// [`LiteError::Backpressure`] until the sync transport drains entries.
92+ /// This bounds RAM usage to the key/pointer overhead regardless of how
93+ /// long the device stays offline; the payloads themselves are on disk.
94+ ///
95+ /// Can also be set via the `NODEDB_LITE_OUTBOUND_QUEUE_CAP` environment
96+ /// variable.
97+ #[ serde( default = "default_outbound_queue_cap" ) ]
98+ pub outbound_queue_cap : usize ,
99+
100+ /// Interval between automatic background flushes, in milliseconds.
101+ /// Default: 1000 (1 second).
102+ ///
103+ /// The auto-flush task calls the global `flush()` every `auto_flush_ms`
104+ /// milliseconds, bounding the data-loss window uniformly across all engines
105+ /// (KV buffer, vector id-map, CRDT deltas, CSR graph, spatial, FTS).
106+ ///
107+ /// **Durability contract**: `await`-ing a write operation (e.g. `kv_put`,
108+ /// `vector_insert`) returning `Ok` does NOT guarantee on-disk durability.
109+ /// Durability is bounded by `auto_flush_ms`. Set to 0 to disable the
110+ /// background task; call `flush()` explicitly to guarantee durability.
111+ #[ serde( default = "default_auto_flush_ms" ) ]
112+ pub auto_flush_ms : u64 ,
113+ }
114+
115+ fn default_outbound_queue_cap ( ) -> usize {
116+ 100_000
84117}
85118
86119fn default_kv_cache_capacity ( ) -> usize {
87120 10_000
88121}
89122
123+ fn default_auto_flush_ms ( ) -> u64 {
124+ 1_000
125+ }
126+
90127fn default_sync_enabled ( ) -> bool {
91128 true
92129}
@@ -112,10 +149,12 @@ impl Default for LiteConfig {
112149 loro_percent : 15 ,
113150 query_percent : 15 ,
114151 sync_enabled : true ,
152+ outbound_queue_cap : default_outbound_queue_cap ( ) ,
115153 argon2_m_cost : default_argon2_m_cost ( ) ,
116154 argon2_t_cost : default_argon2_t_cost ( ) ,
117155 argon2_p_cost : default_argon2_p_cost ( ) ,
118156 kv_cache_capacity : default_kv_cache_capacity ( ) ,
157+ auto_flush_ms : default_auto_flush_ms ( ) ,
119158 }
120159 }
121160}
@@ -126,6 +165,10 @@ impl LiteConfig {
126165 ///
127166 /// Handled variables:
128167 /// - `NODEDB_LITE_MEMORY_MB` — total memory budget in mebibytes (parsed as `usize`)
168+ /// - `NODEDB_LITE_AUTO_FLUSH_MS` — auto-flush interval in milliseconds (parsed as `u64`;
169+ /// 0 = disabled)
170+ /// - `NODEDB_LITE_OUTBOUND_QUEUE_CAP` — max pending entries per durable outbound queue
171+ /// (parsed as `usize`; must be > 0)
129172 pub fn from_env ( ) -> Self {
130173 let mut cfg = Self :: default ( ) ;
131174
@@ -152,6 +195,54 @@ impl LiteConfig {
152195 }
153196 }
154197
198+ if let Ok ( val) = std:: env:: var ( "NODEDB_LITE_OUTBOUND_QUEUE_CAP" ) {
199+ match val. trim ( ) . parse :: < usize > ( ) {
200+ Ok ( cap) if cap > 0 => {
201+ tracing:: info!(
202+ env_var = "NODEDB_LITE_OUTBOUND_QUEUE_CAP" ,
203+ value = cap,
204+ "environment variable override applied"
205+ ) ;
206+ cfg. outbound_queue_cap = cap;
207+ }
208+ Ok ( _) => {
209+ tracing:: warn!(
210+ env_var = "NODEDB_LITE_OUTBOUND_QUEUE_CAP" ,
211+ "value must be > 0; using default 100_000"
212+ ) ;
213+ }
214+ Err ( _) => {
215+ tracing:: warn!(
216+ env_var = "NODEDB_LITE_OUTBOUND_QUEUE_CAP" ,
217+ value = %val,
218+ "ignoring malformed environment variable (expected unsigned integer), \
219+ using default 100_000"
220+ ) ;
221+ }
222+ }
223+ }
224+
225+ if let Ok ( val) = std:: env:: var ( "NODEDB_LITE_AUTO_FLUSH_MS" ) {
226+ match val. trim ( ) . parse :: < u64 > ( ) {
227+ Ok ( ms) => {
228+ tracing:: info!(
229+ env_var = "NODEDB_LITE_AUTO_FLUSH_MS" ,
230+ value = ms,
231+ "environment variable override applied"
232+ ) ;
233+ cfg. auto_flush_ms = ms;
234+ }
235+ Err ( _) => {
236+ tracing:: warn!(
237+ env_var = "NODEDB_LITE_AUTO_FLUSH_MS" ,
238+ value = %val,
239+ "ignoring malformed environment variable (expected unsigned integer), \
240+ using default 1000 ms"
241+ ) ;
242+ }
243+ }
244+ }
245+
155246 cfg
156247 }
157248
@@ -206,6 +297,7 @@ mod tests {
206297 assert_eq ! ( cfg. argon2_m_cost, 19_456 ) ;
207298 assert_eq ! ( cfg. argon2_t_cost, 2 ) ;
208299 assert_eq ! ( cfg. argon2_p_cost, 1 ) ;
300+ assert_eq ! ( cfg. auto_flush_ms, 1_000 ) ;
209301 }
210302
211303 #[ test]
@@ -262,6 +354,37 @@ mod tests {
262354
263355 // Cleanup.
264356 unsafe { std:: env:: remove_var ( "NODEDB_LITE_MEMORY_MB" ) } ;
357+
358+ // NODEDB_LITE_AUTO_FLUSH_MS cases.
359+
360+ // Case A: var absent → default 1000.
361+ unsafe { std:: env:: remove_var ( "NODEDB_LITE_AUTO_FLUSH_MS" ) } ;
362+ let cfg = LiteConfig :: from_env ( ) ;
363+ assert_eq ! (
364+ cfg. auto_flush_ms, 1_000 ,
365+ "absent var should give default 1000 ms"
366+ ) ;
367+
368+ // Case B: valid integer → applied.
369+ unsafe { std:: env:: set_var ( "NODEDB_LITE_AUTO_FLUSH_MS" , "500" ) } ;
370+ let cfg = LiteConfig :: from_env ( ) ;
371+ assert_eq ! ( cfg. auto_flush_ms, 500 , "500 ms should be applied" ) ;
372+
373+ // Case C: 0 = disabled.
374+ unsafe { std:: env:: set_var ( "NODEDB_LITE_AUTO_FLUSH_MS" , "0" ) } ;
375+ let cfg = LiteConfig :: from_env ( ) ;
376+ assert_eq ! ( cfg. auto_flush_ms, 0 , "0 should disable auto-flush" ) ;
377+
378+ // Case D: malformed → fallback to default.
379+ unsafe { std:: env:: set_var ( "NODEDB_LITE_AUTO_FLUSH_MS" , "not_a_number" ) } ;
380+ let cfg = LiteConfig :: from_env ( ) ;
381+ assert_eq ! (
382+ cfg. auto_flush_ms, 1_000 ,
383+ "malformed var should fall back to default 1000 ms"
384+ ) ;
385+
386+ // Cleanup.
387+ unsafe { std:: env:: remove_var ( "NODEDB_LITE_AUTO_FLUSH_MS" ) } ;
265388 }
266389
267390 #[ test]
0 commit comments