lean_ctx/server/
bounded_lock.rs1use std::sync::Arc;
2use std::time::Duration;
3use tokio::sync::{OwnedRwLockReadGuard, OwnedRwLockWriteGuard, RwLock};
4
5const BASE_READ_TIMEOUT: Duration = Duration::from_secs(10);
6const BASE_WRITE_TIMEOUT: Duration = Duration::from_secs(10);
7
8pub fn read<T: Send + Sync + 'static>(
12 lock: &Arc<RwLock<T>>,
13 context: &str,
14) -> Option<OwnedRwLockReadGuard<T>> {
15 let timeout = crate::core::io_health::adaptive_timeout(BASE_READ_TIMEOUT);
16 let lock_clone = lock.clone();
17 let result = tokio::task::block_in_place(|| {
18 let rt = tokio::runtime::Handle::current();
19 rt.block_on(tokio::time::timeout(timeout, lock_clone.read_owned()))
20 });
21 if let Ok(guard) = result {
22 Some(guard)
23 } else {
24 crate::core::io_health::record_freeze();
25 tracing::warn!(
26 "bounded_lock: read timeout ({}ms) for {context}; degrading gracefully",
27 timeout.as_millis()
28 );
29 None
30 }
31}
32
33pub fn write<T: Send + Sync + 'static>(
37 lock: &Arc<RwLock<T>>,
38 context: &str,
39) -> Option<OwnedRwLockWriteGuard<T>> {
40 let timeout = crate::core::io_health::adaptive_timeout(BASE_WRITE_TIMEOUT);
41 let lock_clone = lock.clone();
42 let result = tokio::task::block_in_place(|| {
43 let rt = tokio::runtime::Handle::current();
44 rt.block_on(tokio::time::timeout(timeout, lock_clone.write_owned()))
45 });
46 if let Ok(guard) = result {
47 Some(guard)
48 } else {
49 crate::core::io_health::record_freeze();
50 tracing::warn!(
51 "bounded_lock: write timeout ({}ms) for {context}; degrading gracefully",
52 timeout.as_millis()
53 );
54 None
55 }
56}