1use std::fmt;
42use std::sync::Arc;
43use std::time::Duration;
44
45use anyhow::anyhow;
46use async_trait::async_trait;
47use serde::de::DeserializeOwned;
48use serde::Serialize;
49#[allow(unused_imports)]
50use tower::{Layer, Service, ServiceExt};
51use tower_resilience_circuitbreaker::{
52 CircuitBreakerError, CircuitBreakerLayer, DefaultClassifier, SlidingWindowType,
53};
54
55use crate::storage::{
56 AsyncIterator, DefaultStorageDB, IterItem, Key, List, Map, StorageDB, StorageList, StorageMap,
57};
58use crate::{Result, TimestampMillis};
59
60impl fmt::Debug for StorageMap {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 match self {
64 #[cfg(feature = "sled")]
65 StorageMap::Sled(_) => write!(f, "SledMap"),
66 #[cfg(feature = "redis")]
67 StorageMap::Redis(_) => write!(f, "RedisMap"),
68 #[cfg(feature = "redis-cluster")]
69 StorageMap::RedisCluster(_) => write!(f, "RedisClusterMap"),
70 #[cfg(feature = "redb")]
71 StorageMap::Redb(_) => write!(f, "RedbMap"),
72 }
73 }
74}
75
76#[derive(Debug, Clone)]
84pub struct CircuitBreakerConfig {
85 pub failure_rate_threshold: f64,
87 pub window: WindowConfig,
90 pub minimum_number_of_calls: usize,
92 pub wait_duration_in_open: Duration,
94 pub slow_call_duration_threshold: Duration,
96 pub slow_call_rate_threshold: f64,
98 pub operation_timeout: Option<Duration>,
102 pub name: String,
104}
105
106#[derive(Debug, Clone)]
110pub struct CountBasedWindowConfig {
111 pub sliding_window_size: usize,
113}
114
115impl Default for CountBasedWindowConfig {
116 fn default() -> Self {
117 Self {
118 sliding_window_size: 20,
119 }
120 }
121}
122
123impl From<CountBasedWindowConfig> for WindowConfig {
124 fn from(cfg: CountBasedWindowConfig) -> Self {
125 Self::CountBased(cfg)
126 }
127}
128
129#[derive(Debug, Clone)]
133pub struct TimeBasedWindowConfig {
134 pub sliding_window_duration: Duration,
136 pub sliding_window_size: usize,
138}
139
140impl Default for TimeBasedWindowConfig {
141 fn default() -> Self {
142 Self {
143 sliding_window_duration: Duration::from_secs(45),
144 sliding_window_size: 20,
145 }
146 }
147}
148
149impl From<TimeBasedWindowConfig> for WindowConfig {
150 fn from(cfg: TimeBasedWindowConfig) -> Self {
151 Self::TimeBased(cfg)
152 }
153}
154
155#[derive(Debug, Clone)]
160pub enum WindowConfig {
161 CountBased(CountBasedWindowConfig),
163 TimeBased(TimeBasedWindowConfig),
165}
166
167impl Default for WindowConfig {
168 fn default() -> Self {
169 Self::TimeBased(TimeBasedWindowConfig::default())
170 }
171}
172
173impl Default for CircuitBreakerConfig {
174 fn default() -> Self {
175 Self {
176 failure_rate_threshold: 0.25,
177 window: WindowConfig::default(),
178 minimum_number_of_calls: 10,
179 wait_duration_in_open: Duration::from_secs(30),
180 slow_call_duration_threshold: Duration::from_secs(2),
181 slow_call_rate_threshold: 1.0,
182 operation_timeout: None,
183 name: "storage".into(),
184 }
185 }
186}
187
188#[derive(Debug, Clone)]
194pub enum CBStorageRequest {
195 Insert {
196 key: Vec<u8>,
197 val: Vec<u8>,
198 },
199 Get {
200 key: Vec<u8>,
201 },
202 Remove {
203 key: Vec<u8>,
204 },
205 ContainsKey {
206 key: Vec<u8>,
207 },
208 #[allow(dead_code)]
209 DbMap {
210 name: Vec<u8>,
211 expire: Option<TimestampMillis>,
212 },
213 DbMapRemove {
214 name: Vec<u8>,
215 },
216 DbMapContainsKey {
217 key: Vec<u8>,
218 },
219 #[allow(dead_code)]
220 DbList {
221 name: Vec<u8>,
222 expire: Option<TimestampMillis>,
223 },
224 DbListRemove {
225 name: Vec<u8>,
226 },
227 DbListContainsKey {
228 key: Vec<u8>,
229 },
230 CounterIncr {
231 key: Vec<u8>,
232 increment: isize,
233 },
234 CounterDecr {
235 key: Vec<u8>,
236 decrement: isize,
237 },
238 CounterGet {
239 key: Vec<u8>,
240 },
241 CounterSet {
242 key: Vec<u8>,
243 val: isize,
244 },
245 BatchInsert {
246 key_vals: Vec<(Vec<u8>, Vec<u8>)>,
247 },
248 BatchRemove {
249 keys: Vec<Vec<u8>>,
250 },
251 DbSize,
252 Info,
253 #[cfg(feature = "len")]
254 Len,
255 #[cfg(feature = "ttl")]
256 ExpireAt {
257 key: Vec<u8>,
258 at: TimestampMillis,
259 },
260 #[cfg(feature = "ttl")]
261 Expire {
262 key: Vec<u8>,
263 dur: TimestampMillis,
264 },
265 #[cfg(feature = "ttl")]
266 Ttl {
267 key: Vec<u8>,
268 },
269 MapInsert {
271 map: StorageMap,
272 key: Vec<u8>,
273 val: Vec<u8>,
274 },
275 MapGet {
276 map: StorageMap,
277 key: Vec<u8>,
278 },
279 MapRemove {
280 map: StorageMap,
281 key: Vec<u8>,
282 },
283 MapContainsKey {
284 map: StorageMap,
285 key: Vec<u8>,
286 },
287 MapIsEmpty {
288 map: StorageMap,
289 },
290 MapClear {
291 map: StorageMap,
292 },
293 MapRemoveAndFetch {
294 map: StorageMap,
295 key: Vec<u8>,
296 },
297 MapRemoveWithPrefix {
298 map: StorageMap,
299 prefix: Vec<u8>,
300 },
301 MapBatchInsert {
302 map: StorageMap,
303 key_vals: Vec<(Vec<u8>, Vec<u8>)>,
304 },
305 MapBatchRemove {
306 map: StorageMap,
307 keys: Vec<Vec<u8>>,
308 },
309 #[cfg(feature = "map_len")]
310 MapLen {
311 map: StorageMap,
312 },
313 #[cfg(feature = "ttl")]
314 MapExpireAt {
315 map: StorageMap,
316 at: TimestampMillis,
317 },
318 #[cfg(feature = "ttl")]
319 MapExpire {
320 map: StorageMap,
321 dur: TimestampMillis,
322 },
323 #[cfg(feature = "ttl")]
324 MapTtl {
325 map: StorageMap,
326 },
327 ListPush {
329 list: StorageList,
330 val: Vec<u8>,
331 },
332 ListPushs {
333 list: StorageList,
334 vals: Vec<Vec<u8>>,
335 },
336 ListPushLimit {
337 list: StorageList,
338 val: Vec<u8>,
339 limit: usize,
340 pop_front_if_limited: bool,
341 },
342 ListPop {
343 list: StorageList,
344 },
345 ListGetAll {
346 list: StorageList,
347 },
348 ListGetIndex {
349 list: StorageList,
350 idx: usize,
351 },
352 ListLen {
353 list: StorageList,
354 },
355 ListIsEmpty {
356 list: StorageList,
357 },
358 ListClear {
359 list: StorageList,
360 },
361 #[cfg(feature = "ttl")]
362 ListExpireAt {
363 list: StorageList,
364 at: TimestampMillis,
365 },
366 #[cfg(feature = "ttl")]
367 ListExpire {
368 list: StorageList,
369 dur: TimestampMillis,
370 },
371 #[cfg(feature = "ttl")]
372 ListTtl {
373 list: StorageList,
374 },
375}
376
377pub enum CBStorageResponse {
380 Insert,
381 Get(Option<Vec<u8>>),
382 Remove,
383 ContainsKey(bool),
384 #[allow(dead_code)]
385 DbMap(StorageMap),
386 DbMapRemove,
387 DbMapContainsKey(bool),
388 #[allow(dead_code)]
389 DbList(StorageList),
390 DbListRemove,
391 DbListContainsKey(bool),
392 CounterIncr,
393 CounterDecr,
394 CounterGet(Option<isize>),
395 CounterSet,
396 BatchInsert,
397 BatchRemove,
398 DbSize(usize),
399 Info(serde_json::Value),
400 #[cfg(feature = "len")]
401 Len(usize),
402 #[cfg(feature = "ttl")]
403 ExpireAt(bool),
404 #[cfg(feature = "ttl")]
405 Expire(bool),
406 #[cfg(feature = "ttl")]
407 Ttl(Option<TimestampMillis>),
408 MapInsert,
410 MapGet(Option<Vec<u8>>),
411 MapRemove,
412 MapContainsKey(bool),
413 MapIsEmpty(bool),
414 MapClear,
415 MapRemoveAndFetch(Option<Vec<u8>>),
416 MapRemoveWithPrefix,
417 MapBatchInsert,
418 MapBatchRemove,
419 #[cfg(feature = "map_len")]
420 MapLen(usize),
421 #[cfg(feature = "ttl")]
422 MapExpireAt(bool),
423 #[cfg(feature = "ttl")]
424 MapExpire(bool),
425 #[cfg(feature = "ttl")]
426 MapTtl(Option<TimestampMillis>),
427 ListPush,
429 ListPushs,
430 ListPushLimit(Option<Vec<u8>>),
431 ListPop(Option<Vec<u8>>),
432 ListGetAll(Vec<Vec<u8>>),
433 ListGetIndex(Option<Vec<u8>>),
434 ListLen(usize),
435 ListIsEmpty(bool),
436 ListClear,
437 #[cfg(feature = "ttl")]
438 ListExpireAt(bool),
439 #[cfg(feature = "ttl")]
440 ListExpire(bool),
441 #[cfg(feature = "ttl")]
442 ListTtl(Option<TimestampMillis>),
443}
444
445impl fmt::Debug for CBStorageResponse {
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 match self {
448 CBStorageResponse::Insert => write!(f, "Insert"),
449 CBStorageResponse::Get(v) => f.debug_tuple("Get").field(v).finish(),
450 CBStorageResponse::Remove => write!(f, "Remove"),
451 CBStorageResponse::ContainsKey(b) => f.debug_tuple("ContainsKey").field(b).finish(),
452 CBStorageResponse::DbMap(_) => write!(f, "Map(..)"),
453 CBStorageResponse::DbMapRemove => write!(f, "MapRemove"),
454 CBStorageResponse::DbMapContainsKey(b) => {
455 f.debug_tuple("MapContainsKey").field(b).finish()
456 }
457 CBStorageResponse::DbList(_) => write!(f, "List(..)"),
458 CBStorageResponse::DbListRemove => write!(f, "ListRemove"),
459 CBStorageResponse::DbListContainsKey(b) => {
460 f.debug_tuple("ListContainsKey").field(b).finish()
461 }
462 CBStorageResponse::CounterIncr => write!(f, "CounterIncr"),
463 CBStorageResponse::CounterDecr => write!(f, "CounterDecr"),
464 CBStorageResponse::CounterGet(v) => f.debug_tuple("CounterGet").field(v).finish(),
465 CBStorageResponse::CounterSet => write!(f, "CounterSet"),
466 CBStorageResponse::BatchInsert => write!(f, "BatchInsert"),
467 CBStorageResponse::BatchRemove => write!(f, "BatchRemove"),
468 CBStorageResponse::DbSize(s) => f.debug_tuple("DbSize").field(s).finish(),
469 CBStorageResponse::Info(v) => f.debug_tuple("Info").field(v).finish(),
470 #[cfg(feature = "len")]
471 CBStorageResponse::Len(n) => f.debug_tuple("Len").field(n).finish(),
472 #[cfg(feature = "ttl")]
473 CBStorageResponse::ExpireAt(b) => f.debug_tuple("ExpireAt").field(b).finish(),
474 #[cfg(feature = "ttl")]
475 CBStorageResponse::Expire(b) => f.debug_tuple("Expire").field(b).finish(),
476 #[cfg(feature = "ttl")]
477 CBStorageResponse::Ttl(v) => f.debug_tuple("Ttl").field(v).finish(),
478 CBStorageResponse::MapInsert => write!(f, "MapInsert"),
480 CBStorageResponse::MapGet(v) => f.debug_tuple("MapGet").field(v).finish(),
481 CBStorageResponse::MapRemove => write!(f, "MapRemove"),
482 CBStorageResponse::MapContainsKey(b) => {
483 f.debug_tuple("MapContainsKey").field(b).finish()
484 }
485 CBStorageResponse::MapIsEmpty(b) => f.debug_tuple("MapIsEmpty").field(b).finish(),
486 CBStorageResponse::MapClear => write!(f, "MapClear"),
487 CBStorageResponse::MapRemoveAndFetch(v) => {
488 f.debug_tuple("MapRemoveAndFetch").field(v).finish()
489 }
490 CBStorageResponse::MapRemoveWithPrefix => write!(f, "MapRemoveWithPrefix"),
491 CBStorageResponse::MapBatchInsert => write!(f, "MapBatchInsert"),
492 CBStorageResponse::MapBatchRemove => write!(f, "MapBatchRemove"),
493 #[cfg(feature = "map_len")]
494 CBStorageResponse::MapLen(n) => f.debug_tuple("MapLen").field(n).finish(),
495 #[cfg(feature = "ttl")]
496 CBStorageResponse::MapExpireAt(b) => f.debug_tuple("MapExpireAt").field(b).finish(),
497 #[cfg(feature = "ttl")]
498 CBStorageResponse::MapExpire(b) => f.debug_tuple("MapExpire").field(b).finish(),
499 #[cfg(feature = "ttl")]
500 CBStorageResponse::MapTtl(v) => f.debug_tuple("MapTtl").field(v).finish(),
501 CBStorageResponse::ListPush => write!(f, "ListPush"),
503 CBStorageResponse::ListPushs => write!(f, "ListPushs"),
504 CBStorageResponse::ListPushLimit(v) => f.debug_tuple("ListPushLimit").field(v).finish(),
505 CBStorageResponse::ListPop(v) => f.debug_tuple("ListPop").field(v).finish(),
506 CBStorageResponse::ListGetAll(v) => {
507 f.debug_tuple("ListGetAll").field(&v.len()).finish()
508 }
509 CBStorageResponse::ListGetIndex(v) => f.debug_tuple("ListGetIndex").field(v).finish(),
510 CBStorageResponse::ListLen(n) => f.debug_tuple("ListLen").field(n).finish(),
511 CBStorageResponse::ListIsEmpty(b) => f.debug_tuple("ListIsEmpty").field(b).finish(),
512 CBStorageResponse::ListClear => write!(f, "ListClear"),
513 #[cfg(feature = "ttl")]
514 CBStorageResponse::ListExpireAt(b) => f.debug_tuple("ListExpireAt").field(b).finish(),
515 #[cfg(feature = "ttl")]
516 CBStorageResponse::ListExpire(b) => f.debug_tuple("ListExpire").field(b).finish(),
517 #[cfg(feature = "ttl")]
518 CBStorageResponse::ListTtl(v) => f.debug_tuple("ListTtl").field(v).finish(),
519 }
520 }
521}
522
523#[derive(Clone)]
529pub struct CBStorageService {
530 inner: DefaultStorageDB,
531}
532
533impl tower::Service<CBStorageRequest> for CBStorageService {
534 type Response = CBStorageResponse;
535 type Error = anyhow::Error;
536 type Future =
537 std::pin::Pin<Box<dyn std::future::Future<Output = Result<Self::Response>> + Send>>;
538
539 fn poll_ready(
540 &mut self,
541 _cx: &mut std::task::Context<'_>,
542 ) -> std::task::Poll<std::result::Result<(), Self::Error>> {
543 std::task::Poll::Ready(Ok(()))
544 }
545
546 fn call(&mut self, req: CBStorageRequest) -> Self::Future {
547 let this = self.inner.clone();
548 Box::pin(async move {
549 match req {
550 CBStorageRequest::Insert { key, val } => this
551 .insert_raw(&key, &val)
552 .await
553 .map(|_| CBStorageResponse::Insert),
554 CBStorageRequest::Get { key } => {
555 let val = this.get_raw(&key).await?;
556 Ok(CBStorageResponse::Get(val))
557 }
558 CBStorageRequest::Remove { key } => {
559 this.remove(&key).await.map(|_| CBStorageResponse::Remove)
560 }
561 CBStorageRequest::ContainsKey { key } => this
562 .contains_key(&key)
563 .await
564 .map(CBStorageResponse::ContainsKey),
565 CBStorageRequest::DbMap { name, expire } => {
566 let m = this.map(&name, expire).await;
567 Ok(CBStorageResponse::DbMap(m))
568 }
569 CBStorageRequest::DbMapRemove { name } => this
570 .map_remove(&name)
571 .await
572 .map(|_| CBStorageResponse::DbMapRemove),
573 CBStorageRequest::DbMapContainsKey { key } => this
574 .map_contains_key(&key)
575 .await
576 .map(CBStorageResponse::DbMapContainsKey),
577 CBStorageRequest::DbList { name, expire } => {
578 let l = this.list(&name, expire).await;
579 Ok(CBStorageResponse::DbList(l))
580 }
581 CBStorageRequest::DbListRemove { name } => this
582 .list_remove(&name)
583 .await
584 .map(|_| CBStorageResponse::DbListRemove),
585 CBStorageRequest::DbListContainsKey { key } => this
586 .list_contains_key(&key)
587 .await
588 .map(CBStorageResponse::DbListContainsKey),
589 CBStorageRequest::CounterIncr { key, increment } => this
590 .counter_incr(&key, increment)
591 .await
592 .map(|_| CBStorageResponse::CounterIncr),
593 CBStorageRequest::CounterDecr { key, decrement } => this
594 .counter_decr(&key, decrement)
595 .await
596 .map(|_| CBStorageResponse::CounterDecr),
597 CBStorageRequest::CounterGet { key } => this
598 .counter_get(&key)
599 .await
600 .map(CBStorageResponse::CounterGet),
601 CBStorageRequest::CounterSet { key, val } => this
602 .counter_set(&key, val)
603 .await
604 .map(|_| CBStorageResponse::CounterSet),
605 CBStorageRequest::BatchInsert { key_vals } => this
606 .batch_insert_raw(key_vals)
607 .await
608 .map(|_| CBStorageResponse::BatchInsert),
609 CBStorageRequest::BatchRemove { keys } => this
610 .batch_remove(keys)
611 .await
612 .map(|_| CBStorageResponse::BatchRemove),
613 CBStorageRequest::DbSize => this.db_size().await.map(CBStorageResponse::DbSize),
614 CBStorageRequest::Info => this.info().await.map(CBStorageResponse::Info),
615 #[cfg(feature = "len")]
616 CBStorageRequest::Len => this.len().await.map(CBStorageResponse::Len),
617 #[cfg(feature = "ttl")]
618 CBStorageRequest::ExpireAt { key, at } => this
619 .expire_at(&key, at)
620 .await
621 .map(CBStorageResponse::ExpireAt),
622 #[cfg(feature = "ttl")]
623 CBStorageRequest::Expire { key, dur } => {
624 this.expire(&key, dur).await.map(CBStorageResponse::Expire)
625 }
626 #[cfg(feature = "ttl")]
627 CBStorageRequest::Ttl { key } => this.ttl(&key).await.map(CBStorageResponse::Ttl),
628 CBStorageRequest::MapInsert { map, key, val } => map
630 .insert_raw(&key, &val)
631 .await
632 .map(|_| CBStorageResponse::MapInsert),
633 CBStorageRequest::MapGet { map, key } => {
634 map.get_raw(&key).await.map(CBStorageResponse::MapGet)
635 }
636 CBStorageRequest::MapRemove { map, key } => {
637 map.remove(&key).await.map(|_| CBStorageResponse::MapRemove)
638 }
639 CBStorageRequest::MapContainsKey { map, key } => map
640 .contains_key(&key)
641 .await
642 .map(CBStorageResponse::MapContainsKey),
643 CBStorageRequest::MapIsEmpty { map } => {
644 map.is_empty().await.map(CBStorageResponse::MapIsEmpty)
645 }
646 CBStorageRequest::MapClear { map } => {
647 map.clear().await.map(|_| CBStorageResponse::MapClear)
648 }
649 CBStorageRequest::MapRemoveAndFetch { map, key } => map
650 .remove_and_fetch_raw(&key)
651 .await
652 .map(CBStorageResponse::MapRemoveAndFetch),
653 CBStorageRequest::MapRemoveWithPrefix { map, prefix } => map
654 .remove_with_prefix(&prefix)
655 .await
656 .map(|_| CBStorageResponse::MapRemoveWithPrefix),
657 CBStorageRequest::MapBatchInsert { map, key_vals } => map
658 .batch_insert_raw(key_vals)
659 .await
660 .map(|_| CBStorageResponse::MapBatchInsert),
661 CBStorageRequest::MapBatchRemove { map, keys } => map
662 .batch_remove(keys)
663 .await
664 .map(|_| CBStorageResponse::MapBatchRemove),
665 #[cfg(feature = "map_len")]
666 CBStorageRequest::MapLen { map } => map.len().await.map(CBStorageResponse::MapLen),
667 #[cfg(feature = "ttl")]
668 CBStorageRequest::MapExpireAt { map, at } => {
669 map.expire_at(at).await.map(CBStorageResponse::MapExpireAt)
670 }
671 #[cfg(feature = "ttl")]
672 CBStorageRequest::MapExpire { map, dur } => {
673 map.expire(dur).await.map(CBStorageResponse::MapExpire)
674 }
675 #[cfg(feature = "ttl")]
676 CBStorageRequest::MapTtl { map } => map.ttl().await.map(CBStorageResponse::MapTtl),
677 CBStorageRequest::ListPush { list, val } => list
679 .push_raw(&val)
680 .await
681 .map(|_| CBStorageResponse::ListPush),
682 CBStorageRequest::ListPushs { list, vals } => list
683 .pushs_raw(vals)
684 .await
685 .map(|_| CBStorageResponse::ListPushs),
686 CBStorageRequest::ListPushLimit {
687 list,
688 val,
689 limit,
690 pop_front_if_limited,
691 } => list
692 .push_limit_raw(&val, limit, pop_front_if_limited)
693 .await
694 .map(CBStorageResponse::ListPushLimit),
695 CBStorageRequest::ListPop { list } => {
696 list.pop_raw().await.map(CBStorageResponse::ListPop)
697 }
698 CBStorageRequest::ListGetAll { list } => {
699 list.all_raw().await.map(CBStorageResponse::ListGetAll)
700 }
701 CBStorageRequest::ListGetIndex { list, idx } => list
702 .get_index_raw(idx)
703 .await
704 .map(CBStorageResponse::ListGetIndex),
705 CBStorageRequest::ListLen { list } => {
706 list.len().await.map(CBStorageResponse::ListLen)
707 }
708 CBStorageRequest::ListIsEmpty { list } => {
709 list.is_empty().await.map(CBStorageResponse::ListIsEmpty)
710 }
711 CBStorageRequest::ListClear { list } => {
712 list.clear().await.map(|_| CBStorageResponse::ListClear)
713 }
714 #[cfg(feature = "ttl")]
715 CBStorageRequest::ListExpireAt { list, at } => list
716 .expire_at(at)
717 .await
718 .map(CBStorageResponse::ListExpireAt),
719 #[cfg(feature = "ttl")]
720 CBStorageRequest::ListExpire { list, dur } => {
721 list.expire(dur).await.map(CBStorageResponse::ListExpire)
722 }
723 #[cfg(feature = "ttl")]
724 CBStorageRequest::ListTtl { list } => {
725 list.ttl().await.map(CBStorageResponse::ListTtl)
726 }
727 }
728 })
729 }
730}
731
732#[derive(Clone)]
745pub(crate) struct CbTimeoutWrapper<S> {
746 inner: S,
747 timeout: Option<Duration>,
748}
749
750impl<S, Req> tower::Service<Req> for CbTimeoutWrapper<S>
751where
752 S: tower::Service<Req> + Clone + Send + 'static,
753 S::Response: Send + 'static,
754 S::Error: Into<anyhow::Error> + Send + 'static,
755 S::Future: Send + 'static,
756 Req: Send + 'static,
757{
758 type Response = S::Response;
759 type Error = anyhow::Error;
760 type Future = std::pin::Pin<
761 Box<
762 dyn std::future::Future<Output = std::result::Result<Self::Response, Self::Error>>
763 + Send,
764 >,
765 >;
766
767 fn poll_ready(
768 &mut self,
769 cx: &mut std::task::Context<'_>,
770 ) -> std::task::Poll<std::result::Result<(), Self::Error>> {
771 self.inner.poll_ready(cx).map_err(|e| e.into())
772 }
773
774 fn call(&mut self, req: Req) -> Self::Future {
775 let fut = self.inner.call(req);
776 let timeout = self.timeout;
777 Box::pin(async move {
778 match timeout {
779 Some(dur) => match tokio::time::timeout(dur, fut).await {
780 Ok(r) => r.map_err(|e| e.into()),
781 Err(_) => Err(anyhow!("operation timed out after {:?}", dur)),
782 },
783 None => fut.await.map_err(|e| e.into()),
784 }
785 })
786 }
787}
788
789fn build_db_cb(
795 inner: CBStorageService,
796 config: &CircuitBreakerConfig,
797 name: &str,
798) -> tower_resilience_circuitbreaker::CircuitBreaker<
799 CbTimeoutWrapper<CBStorageService>,
800 DefaultClassifier,
801> {
802 let timeout_svc = CbTimeoutWrapper {
803 inner,
804 timeout: config.operation_timeout,
805 };
806 build_cb_inner(timeout_svc, config, name)
807}
808
809fn build_cb_inner<S, Req>(
810 inner: S,
811 config: &CircuitBreakerConfig,
812 name: &str,
813) -> tower_resilience_circuitbreaker::CircuitBreaker<S, DefaultClassifier>
814where
815 S: tower::Service<Req> + Clone + Send + 'static,
816 S::Response: Send + 'static,
817 S::Error: Into<anyhow::Error> + Send + 'static,
818 S::Future: Send + 'static,
819 Req: Send + 'static,
820{
821 let n = name.to_owned();
822 let mut builder = CircuitBreakerLayer::builder()
823 .name(name)
824 .failure_rate_threshold(config.failure_rate_threshold)
825 .minimum_number_of_calls(config.minimum_number_of_calls)
826 .wait_duration_in_open(config.wait_duration_in_open)
827 .slow_call_duration_threshold(config.slow_call_duration_threshold)
828 .slow_call_rate_threshold(config.slow_call_rate_threshold);
829
830 match &config.window {
831 WindowConfig::CountBased(cfg) => {
832 builder = builder
833 .sliding_window_type(SlidingWindowType::CountBased)
834 .sliding_window_size(cfg.sliding_window_size);
835 }
836 WindowConfig::TimeBased(cfg) => {
837 builder = builder
838 .sliding_window_type(SlidingWindowType::TimeBased)
839 .sliding_window_duration(cfg.sliding_window_duration)
840 .sliding_window_size(cfg.sliding_window_size);
841 }
842 }
843
844 builder
845 .on_state_transition(move |from, to| {
846 log::info!(
847 "[circuit-breaker:{}] state changed: {:?} -> {:?}",
848 n,
849 from,
850 to
851 );
852 })
853 .build()
854 .layer(inner)
855}
856
857type SharedBreaker = Arc<
861 tower_resilience_circuitbreaker::CircuitBreaker<
862 CbTimeoutWrapper<CBStorageService>,
863 DefaultClassifier,
864 >,
865>;
866
867pub struct CircuitBrokenDB {
877 service: SharedBreaker,
879 config: CircuitBreakerConfig,
880 inner: DefaultStorageDB,
884}
885
886impl CircuitBrokenDB {
887 pub fn new(db: DefaultStorageDB, config: CircuitBreakerConfig) -> Self {
889 let name = config.name.clone();
890 let inner = db.clone();
891 let chain_svc = CBStorageService { inner: db };
892 let service = Arc::new(build_db_cb(chain_svc, &config, &name));
895 Self {
896 service,
897 config,
898 inner,
899 }
900 }
901
902 pub fn config(&self) -> &CircuitBreakerConfig {
904 &self.config
905 }
906
907 async fn raw_call(&self, req: CBStorageRequest) -> Result<CBStorageResponse> {
908 let mut svc = self.service.as_ref().clone();
913
914 match svc.call(req).await {
915 Ok(r) => Ok(r),
916 Err(CircuitBreakerError::OpenCircuit) => Err(anyhow!(
917 "storage unavailable (circuit breaker open for '{}')",
918 self.config.name
919 )),
920 Err(CircuitBreakerError::Inner(e)) => Err(e),
921 }
922 }
923
924 pub async fn cb_info(&self) -> serde_json::Value {
931 let metrics = self.service.metrics().await;
932
933 serde_json::json!({
934 "name": self.config.name,
935 "state": format!("{:?}", metrics.state),
936 "state_code": metrics.state as u8,
937 "is_open": self.service.is_open(),
938 "metrics": {
939 "total_calls": metrics.total_calls,
940 "failure_count": metrics.failure_count,
941 "success_count": metrics.success_count,
942 "slow_call_count": metrics.slow_call_count,
943 "failure_rate": metrics.failure_rate,
944 "slow_call_rate": metrics.slow_call_rate,
945 "time_since_state_change_ms": metrics.time_since_state_change.as_millis() as u64,
946 },
947 "config": {
948 "failure_rate_threshold": self.config.failure_rate_threshold,
949 "window": match &self.config.window {
950 WindowConfig::CountBased(cfg) => serde_json::json!({
951 "type": "CountBased",
952 "sliding_window_size": cfg.sliding_window_size,
953 }),
954 WindowConfig::TimeBased(cfg) => serde_json::json!({
955 "type": "TimeBased",
956 "sliding_window_duration_ms": cfg.sliding_window_duration.as_millis() as u64,
957 "sliding_window_size": cfg.sliding_window_size,
958 }),
959 },
960 "minimum_number_of_calls": self.config.minimum_number_of_calls,
961 "wait_duration_in_open_ms": self.config.wait_duration_in_open.as_millis() as u64,
962 "slow_call_duration_threshold_ms": self.config.slow_call_duration_threshold.as_millis() as u64,
963 "slow_call_rate_threshold": self.config.slow_call_rate_threshold,
964 "operation_timeout_ms": self.config.operation_timeout.map(|d| d.as_millis() as u64),
965 },
966 })
967 }
968}
969
970impl Clone for CircuitBrokenDB {
971 fn clone(&self) -> Self {
972 Self {
973 service: Arc::clone(&self.service),
974 config: self.config.clone(),
975 inner: self.inner.clone(),
976 }
977 }
978}
979
980#[async_trait]
985impl StorageDB for CircuitBrokenDB {
986 type MapType = CircuitBrokenMap;
987 type ListType = CircuitBrokenList;
988
989 async fn map<N: AsRef<[u8]> + Sync + Send>(
990 &self,
991 name: N,
992 expire: Option<TimestampMillis>,
993 ) -> Self::MapType {
994 let raw = self.inner.map(name, expire).await;
995 CircuitBrokenMap::new(raw, Arc::clone(&self.service), self.config.name.clone())
996 }
997
998 async fn map_remove<K>(&self, name: K) -> Result<()>
999 where
1000 K: AsRef<[u8]> + Sync + Send,
1001 {
1002 self.raw_call(CBStorageRequest::DbMapRemove {
1003 name: name.as_ref().to_vec(),
1004 })
1005 .await
1006 .map(|_| ())
1007 }
1008
1009 async fn map_contains_key<K: AsRef<[u8]> + Sync + Send>(&self, key: K) -> Result<bool> {
1010 match self
1011 .raw_call(CBStorageRequest::DbMapContainsKey {
1012 key: key.as_ref().to_vec(),
1013 })
1014 .await?
1015 {
1016 CBStorageResponse::DbMapContainsKey(b) => Ok(b),
1017 _ => Err(anyhow!("unexpected response type for map_contains_key()")),
1018 }
1019 }
1020
1021 async fn list<V: AsRef<[u8]> + Sync + Send>(
1022 &self,
1023 name: V,
1024 expire: Option<TimestampMillis>,
1025 ) -> Self::ListType {
1026 let raw = self.inner.list(name, expire).await;
1027 CircuitBrokenList::new(raw, Arc::clone(&self.service), self.config.name.clone())
1028 }
1029
1030 async fn list_remove<K>(&self, name: K) -> Result<()>
1031 where
1032 K: AsRef<[u8]> + Sync + Send,
1033 {
1034 self.raw_call(CBStorageRequest::DbListRemove {
1035 name: name.as_ref().to_vec(),
1036 })
1037 .await
1038 .map(|_| ())
1039 }
1040
1041 async fn list_contains_key<K: AsRef<[u8]> + Sync + Send>(&self, key: K) -> Result<bool> {
1042 match self
1043 .raw_call(CBStorageRequest::DbListContainsKey {
1044 key: key.as_ref().to_vec(),
1045 })
1046 .await?
1047 {
1048 CBStorageResponse::DbListContainsKey(b) => Ok(b),
1049 _ => Err(anyhow!("unexpected response type for list_contains_key()")),
1050 }
1051 }
1052
1053 async fn insert<K, V>(&self, key: K, val: &V) -> Result<()>
1054 where
1055 K: AsRef<[u8]> + Sync + Send,
1056 V: Serialize + Sync + Send,
1057 {
1058 let bytes = postcard::to_stdvec(val)?;
1059 self.raw_call(CBStorageRequest::Insert {
1060 key: key.as_ref().to_vec(),
1061 val: bytes,
1062 })
1063 .await
1064 .map(|_| ())
1065 }
1066
1067 async fn get<K, V>(&self, key: K) -> Result<Option<V>>
1068 where
1069 K: AsRef<[u8]> + Sync + Send,
1070 V: DeserializeOwned + Sync + Send,
1071 {
1072 let req = CBStorageRequest::Get {
1073 key: key.as_ref().to_vec(),
1074 };
1075 match self.raw_call(req).await? {
1076 CBStorageResponse::Get(Some(bytes)) => Ok(Some(postcard::from_bytes(&bytes)?)),
1077 CBStorageResponse::Get(None) => Ok(None),
1078 _ => Err(anyhow!("unexpected response type for get()")),
1079 }
1080 }
1081
1082 async fn remove<K>(&self, key: K) -> Result<()>
1083 where
1084 K: AsRef<[u8]> + Sync + Send,
1085 {
1086 self.raw_call(CBStorageRequest::Remove {
1087 key: key.as_ref().to_vec(),
1088 })
1089 .await
1090 .map(|_| ())
1091 }
1092
1093 async fn batch_insert<V>(&self, key_vals: Vec<(Key, V)>) -> Result<()>
1094 where
1095 V: Serialize + Sync + Send,
1096 {
1097 let mut pairs = Vec::with_capacity(key_vals.len());
1098 for (k, v) in key_vals {
1099 pairs.push((k, postcard::to_stdvec(&v)?));
1100 }
1101 self.raw_call(CBStorageRequest::BatchInsert { key_vals: pairs })
1102 .await
1103 .map(|_| ())
1104 }
1105
1106 async fn batch_remove(&self, keys: Vec<Key>) -> Result<()> {
1107 self.raw_call(CBStorageRequest::BatchRemove { keys })
1108 .await
1109 .map(|_| ())
1110 }
1111
1112 async fn counter_incr<K>(&self, key: K, increment: isize) -> Result<()>
1113 where
1114 K: AsRef<[u8]> + Sync + Send,
1115 {
1116 self.raw_call(CBStorageRequest::CounterIncr {
1117 key: key.as_ref().to_vec(),
1118 increment,
1119 })
1120 .await
1121 .map(|_| ())
1122 }
1123
1124 async fn counter_decr<K>(&self, key: K, decrement: isize) -> Result<()>
1125 where
1126 K: AsRef<[u8]> + Sync + Send,
1127 {
1128 self.raw_call(CBStorageRequest::CounterDecr {
1129 key: key.as_ref().to_vec(),
1130 decrement,
1131 })
1132 .await
1133 .map(|_| ())
1134 }
1135
1136 async fn counter_get<K>(&self, key: K) -> Result<Option<isize>>
1137 where
1138 K: AsRef<[u8]> + Sync + Send,
1139 {
1140 match self
1141 .raw_call(CBStorageRequest::CounterGet {
1142 key: key.as_ref().to_vec(),
1143 })
1144 .await?
1145 {
1146 CBStorageResponse::CounterGet(v) => Ok(v),
1147 _ => Err(anyhow!("unexpected response type for counter_get()")),
1148 }
1149 }
1150
1151 async fn counter_set<K>(&self, key: K, val: isize) -> Result<()>
1152 where
1153 K: AsRef<[u8]> + Sync + Send,
1154 {
1155 self.raw_call(CBStorageRequest::CounterSet {
1156 key: key.as_ref().to_vec(),
1157 val,
1158 })
1159 .await
1160 .map(|_| ())
1161 }
1162
1163 async fn contains_key<K: AsRef<[u8]> + Sync + Send>(&self, key: K) -> Result<bool> {
1164 match self
1165 .raw_call(CBStorageRequest::ContainsKey {
1166 key: key.as_ref().to_vec(),
1167 })
1168 .await?
1169 {
1170 CBStorageResponse::ContainsKey(b) => Ok(b),
1171 _ => Err(anyhow!("unexpected response type for contains_key()")),
1172 }
1173 }
1174
1175 #[cfg(feature = "len")]
1176 async fn len(&self) -> Result<usize> {
1177 match self.raw_call(CBStorageRequest::Len).await? {
1178 CBStorageResponse::Len(n) => Ok(n),
1179 _ => Err(anyhow!("unexpected response type for len()")),
1180 }
1181 }
1182
1183 async fn db_size(&self) -> Result<usize> {
1184 match self.raw_call(CBStorageRequest::DbSize).await? {
1185 CBStorageResponse::DbSize(s) => Ok(s),
1186 _ => Err(anyhow!("unexpected response type for db_size()")),
1187 }
1188 }
1189
1190 #[cfg(feature = "ttl")]
1191 async fn expire_at<K>(&self, key: K, at: TimestampMillis) -> Result<bool>
1192 where
1193 K: AsRef<[u8]> + Sync + Send,
1194 {
1195 match self
1196 .raw_call(CBStorageRequest::ExpireAt {
1197 key: key.as_ref().to_vec(),
1198 at,
1199 })
1200 .await?
1201 {
1202 CBStorageResponse::ExpireAt(b) => Ok(b),
1203 _ => Err(anyhow!("unexpected response type for expire_at()")),
1204 }
1205 }
1206
1207 #[cfg(feature = "ttl")]
1208 async fn expire<K>(&self, key: K, dur: TimestampMillis) -> Result<bool>
1209 where
1210 K: AsRef<[u8]> + Sync + Send,
1211 {
1212 match self
1213 .raw_call(CBStorageRequest::Expire {
1214 key: key.as_ref().to_vec(),
1215 dur,
1216 })
1217 .await?
1218 {
1219 CBStorageResponse::Expire(b) => Ok(b),
1220 _ => Err(anyhow!("unexpected response type for expire()")),
1221 }
1222 }
1223
1224 #[cfg(feature = "ttl")]
1225 async fn ttl<K>(&self, key: K) -> Result<Option<TimestampMillis>>
1226 where
1227 K: AsRef<[u8]> + Sync + Send,
1228 {
1229 match self
1230 .raw_call(CBStorageRequest::Ttl {
1231 key: key.as_ref().to_vec(),
1232 })
1233 .await?
1234 {
1235 CBStorageResponse::Ttl(v) => Ok(v),
1236 _ => Err(anyhow!("unexpected response type for ttl()")),
1237 }
1238 }
1239
1240 async fn map_iter<'a>(
1241 &'a mut self,
1242 ) -> Result<Box<dyn AsyncIterator<Item = Result<StorageMap>> + Send + 'a>> {
1243 self.inner.map_iter().await
1244 }
1245
1246 async fn list_iter<'a>(
1247 &'a mut self,
1248 ) -> Result<Box<dyn AsyncIterator<Item = Result<StorageList>> + Send + 'a>> {
1249 self.inner.list_iter().await
1250 }
1251
1252 async fn scan<'a, P>(
1253 &'a mut self,
1254 pattern: P,
1255 ) -> Result<Box<dyn AsyncIterator<Item = Result<Key>> + Send + 'a>>
1256 where
1257 P: AsRef<[u8]> + Send + Sync,
1258 {
1259 self.inner.scan(pattern).await
1260 }
1261
1262 async fn info(&self) -> Result<serde_json::Value> {
1263 let mut base = match self.raw_call(CBStorageRequest::Info).await {
1264 Ok(CBStorageResponse::Info(v)) => v,
1265 Err(e) => serde_json::Value::String(e.to_string()),
1266 _ => return Err(anyhow!("unexpected response type for info()")),
1267 };
1268
1269 if let Some(obj) = base.as_object_mut() {
1270 obj.insert("circuit_breaker".into(), self.cb_info().await);
1271 } else {
1272 let cb_state = self.cb_info().await;
1273 base = serde_json::json!({
1274 "storage": base,
1275 "circuit_breaker": cb_state,
1276 });
1277 }
1278
1279 Ok(base)
1280 }
1281}
1282
1283pub struct CircuitBrokenMap {
1295 breaker: SharedBreaker,
1297 inner: StorageMap,
1299 name: String,
1301}
1302
1303impl Clone for CircuitBrokenMap {
1304 fn clone(&self) -> Self {
1305 Self {
1306 breaker: Arc::clone(&self.breaker),
1307 inner: self.inner.clone(),
1308 name: self.name.clone(),
1309 }
1310 }
1311}
1312
1313impl CircuitBrokenMap {
1314 fn new(m: StorageMap, breaker: SharedBreaker, name: String) -> Self {
1315 Self {
1316 breaker,
1317 inner: m,
1318 name,
1319 }
1320 }
1321}
1322
1323#[async_trait]
1326impl Map for CircuitBrokenMap {
1327 fn name(&self) -> &[u8] {
1328 self.inner.name()
1329 }
1330
1331 async fn insert<K, V>(&self, key: K, val: &V) -> Result<()>
1332 where
1333 K: AsRef<[u8]> + Sync + Send,
1334 V: Serialize + Sync + Send + ?Sized,
1335 {
1336 let bytes = postcard::to_stdvec(val)?;
1337 let mut svc = self.breaker.as_ref().clone();
1338 svc.call(CBStorageRequest::MapInsert {
1339 map: self.inner.clone(),
1340 key: key.as_ref().to_vec(),
1341 val: bytes,
1342 })
1343 .await
1344 .map_err(|_| {
1345 anyhow!(
1346 "storage unavailable (circuit breaker open for '{}')",
1347 self.name
1348 )
1349 })?;
1350 Ok(())
1351 }
1352
1353 async fn get<K, V>(&self, key: K) -> Result<Option<V>>
1354 where
1355 K: AsRef<[u8]> + Sync + Send,
1356 V: DeserializeOwned + Sync + Send,
1357 {
1358 let mut svc = self.breaker.as_ref().clone();
1359 let resp = svc
1360 .call(CBStorageRequest::MapGet {
1361 map: self.inner.clone(),
1362 key: key.as_ref().to_vec(),
1363 })
1364 .await
1365 .map_err(|_| {
1366 anyhow!(
1367 "storage unavailable (circuit breaker open for '{}')",
1368 self.name
1369 )
1370 })?;
1371 match resp {
1372 CBStorageResponse::MapGet(Some(bytes)) => Ok(Some(postcard::from_bytes(&bytes)?)),
1373 CBStorageResponse::MapGet(None) => Ok(None),
1374 _ => Err(anyhow!("unexpected response type for map::get()")),
1375 }
1376 }
1377
1378 async fn remove<K>(&self, key: K) -> Result<()>
1379 where
1380 K: AsRef<[u8]> + Sync + Send,
1381 {
1382 let mut svc = self.breaker.as_ref().clone();
1383 svc.call(CBStorageRequest::MapRemove {
1384 map: self.inner.clone(),
1385 key: key.as_ref().to_vec(),
1386 })
1387 .await
1388 .map_err(|_| {
1389 anyhow!(
1390 "storage unavailable (circuit breaker open for '{}')",
1391 self.name
1392 )
1393 })?;
1394 Ok(())
1395 }
1396
1397 async fn contains_key<K: AsRef<[u8]> + Sync + Send>(&self, key: K) -> Result<bool> {
1398 let mut svc = self.breaker.as_ref().clone();
1399 let resp = svc
1400 .call(CBStorageRequest::MapContainsKey {
1401 map: self.inner.clone(),
1402 key: key.as_ref().to_vec(),
1403 })
1404 .await
1405 .map_err(|_| {
1406 anyhow!(
1407 "storage unavailable (circuit breaker open for '{}')",
1408 self.name
1409 )
1410 })?;
1411 match resp {
1412 CBStorageResponse::MapContainsKey(b) => Ok(b),
1413 _ => Err(anyhow!("unexpected response type for map::contains_key()")),
1414 }
1415 }
1416
1417 #[cfg(feature = "map_len")]
1418 async fn len(&self) -> Result<usize> {
1419 let mut svc = self.breaker.as_ref().clone();
1420 let resp = svc
1421 .call(CBStorageRequest::MapLen {
1422 map: self.inner.clone(),
1423 })
1424 .await
1425 .map_err(|_| {
1426 anyhow!(
1427 "storage unavailable (circuit breaker open for '{}')",
1428 self.name
1429 )
1430 })?;
1431 match resp {
1432 CBStorageResponse::MapLen(n) => Ok(n),
1433 _ => Err(anyhow!("unexpected response type for map::len()")),
1434 }
1435 }
1436
1437 async fn is_empty(&self) -> Result<bool> {
1438 let mut svc = self.breaker.as_ref().clone();
1439 let resp = svc
1440 .call(CBStorageRequest::MapIsEmpty {
1441 map: self.inner.clone(),
1442 })
1443 .await
1444 .map_err(|_| {
1445 anyhow!(
1446 "storage unavailable (circuit breaker open for '{}')",
1447 self.name
1448 )
1449 })?;
1450 match resp {
1451 CBStorageResponse::MapIsEmpty(b) => Ok(b),
1452 _ => Err(anyhow!("unexpected response type for map::is_empty()")),
1453 }
1454 }
1455
1456 async fn clear(&self) -> Result<()> {
1457 let mut svc = self.breaker.as_ref().clone();
1458 svc.call(CBStorageRequest::MapClear {
1459 map: self.inner.clone(),
1460 })
1461 .await
1462 .map_err(|_| {
1463 anyhow!(
1464 "storage unavailable (circuit breaker open for '{}')",
1465 self.name
1466 )
1467 })?;
1468 Ok(())
1469 }
1470
1471 async fn remove_and_fetch<K, V>(&self, key: K) -> Result<Option<V>>
1472 where
1473 K: AsRef<[u8]> + Sync + Send,
1474 V: DeserializeOwned + Sync + Send,
1475 {
1476 let mut svc = self.breaker.as_ref().clone();
1477 let resp = svc
1478 .call(CBStorageRequest::MapRemoveAndFetch {
1479 map: self.inner.clone(),
1480 key: key.as_ref().to_vec(),
1481 })
1482 .await
1483 .map_err(|_| {
1484 anyhow!(
1485 "storage unavailable (circuit breaker open for '{}')",
1486 self.name
1487 )
1488 })?;
1489 match resp {
1490 CBStorageResponse::MapRemoveAndFetch(Some(bytes)) => {
1491 Ok(Some(postcard::from_bytes(&bytes)?))
1492 }
1493 CBStorageResponse::MapRemoveAndFetch(None) => Ok(None),
1494 _ => Err(anyhow!(
1495 "unexpected response type for map::remove_and_fetch()"
1496 )),
1497 }
1498 }
1499
1500 async fn remove_with_prefix<K>(&self, prefix: K) -> Result<()>
1501 where
1502 K: AsRef<[u8]> + Sync + Send,
1503 {
1504 let mut svc = self.breaker.as_ref().clone();
1505 svc.call(CBStorageRequest::MapRemoveWithPrefix {
1506 map: self.inner.clone(),
1507 prefix: prefix.as_ref().to_vec(),
1508 })
1509 .await
1510 .map_err(|_| {
1511 anyhow!(
1512 "storage unavailable (circuit breaker open for '{}')",
1513 self.name
1514 )
1515 })?;
1516 Ok(())
1517 }
1518
1519 async fn batch_insert<V>(&self, key_vals: Vec<(Key, V)>) -> Result<()>
1520 where
1521 V: Serialize + Sync + Send,
1522 {
1523 let mut pairs = Vec::with_capacity(key_vals.len());
1524 for (k, v) in key_vals {
1525 pairs.push((k, postcard::to_stdvec(&v)?));
1526 }
1527 let mut svc = self.breaker.as_ref().clone();
1528 svc.call(CBStorageRequest::MapBatchInsert {
1529 map: self.inner.clone(),
1530 key_vals: pairs,
1531 })
1532 .await
1533 .map_err(|_| {
1534 anyhow!(
1535 "storage unavailable (circuit breaker open for '{}')",
1536 self.name
1537 )
1538 })?;
1539 Ok(())
1540 }
1541
1542 async fn batch_remove(&self, keys: Vec<Key>) -> Result<()> {
1543 let mut svc = self.breaker.as_ref().clone();
1544 svc.call(CBStorageRequest::MapBatchRemove {
1545 map: self.inner.clone(),
1546 keys,
1547 })
1548 .await
1549 .map_err(|_| {
1550 anyhow!(
1551 "storage unavailable (circuit breaker open for '{}')",
1552 self.name
1553 )
1554 })?;
1555 Ok(())
1556 }
1557
1558 async fn iter<'a, V>(
1560 &'a mut self,
1561 ) -> Result<Box<dyn AsyncIterator<Item = IterItem<V>> + Send + 'a>>
1562 where
1563 V: DeserializeOwned + Sync + Send + 'a + 'static,
1564 {
1565 self.inner.iter().await
1566 }
1567
1568 async fn key_iter<'a>(
1569 &'a mut self,
1570 ) -> Result<Box<dyn AsyncIterator<Item = Result<Key>> + Send + 'a>> {
1571 self.inner.key_iter().await
1572 }
1573
1574 async fn prefix_iter<'a, P, V>(
1575 &'a mut self,
1576 prefix: P,
1577 ) -> Result<Box<dyn AsyncIterator<Item = IterItem<V>> + Send + 'a>>
1578 where
1579 P: AsRef<[u8]> + Send + Sync,
1580 V: DeserializeOwned + Sync + Send + 'a + 'static,
1581 {
1582 self.inner.prefix_iter(prefix).await
1583 }
1584
1585 #[cfg(feature = "ttl")]
1586 async fn expire_at(&self, at: TimestampMillis) -> Result<bool> {
1587 let mut svc = self.breaker.as_ref().clone();
1588 let resp = svc
1589 .call(CBStorageRequest::MapExpireAt {
1590 map: self.inner.clone(),
1591 at,
1592 })
1593 .await
1594 .map_err(|_| {
1595 anyhow!(
1596 "storage unavailable (circuit breaker open for '{}')",
1597 self.name
1598 )
1599 })?;
1600 match resp {
1601 CBStorageResponse::MapExpireAt(b) => Ok(b),
1602 _ => Err(anyhow!("unexpected response type for map::expire_at()")),
1603 }
1604 }
1605
1606 #[cfg(feature = "ttl")]
1607 async fn expire(&self, dur: TimestampMillis) -> Result<bool> {
1608 let mut svc = self.breaker.as_ref().clone();
1609 let resp = svc
1610 .call(CBStorageRequest::MapExpire {
1611 map: self.inner.clone(),
1612 dur,
1613 })
1614 .await
1615 .map_err(|_| {
1616 anyhow!(
1617 "storage unavailable (circuit breaker open for '{}')",
1618 self.name
1619 )
1620 })?;
1621 match resp {
1622 CBStorageResponse::MapExpire(b) => Ok(b),
1623 _ => Err(anyhow!("unexpected response type for map::expire()")),
1624 }
1625 }
1626
1627 #[cfg(feature = "ttl")]
1628 async fn ttl(&self) -> Result<Option<TimestampMillis>> {
1629 let mut svc = self.breaker.as_ref().clone();
1630 let resp = svc
1631 .call(CBStorageRequest::MapTtl {
1632 map: self.inner.clone(),
1633 })
1634 .await
1635 .map_err(|_| {
1636 anyhow!(
1637 "storage unavailable (circuit breaker open for '{}')",
1638 self.name
1639 )
1640 })?;
1641 match resp {
1642 CBStorageResponse::MapTtl(v) => Ok(v),
1643 _ => Err(anyhow!("unexpected response type for map::ttl()")),
1644 }
1645 }
1646}
1647
1648pub struct CircuitBrokenList {
1660 breaker: SharedBreaker,
1662 inner: StorageList,
1664 name: String,
1666}
1667
1668impl Clone for CircuitBrokenList {
1669 fn clone(&self) -> Self {
1670 Self {
1671 breaker: Arc::clone(&self.breaker),
1672 inner: self.inner.clone(),
1673 name: self.name.clone(),
1674 }
1675 }
1676}
1677
1678impl CircuitBrokenList {
1679 fn new(l: StorageList, breaker: SharedBreaker, name: String) -> Self {
1680 Self {
1681 breaker,
1682 inner: l,
1683 name,
1684 }
1685 }
1686}
1687
1688#[async_trait]
1691impl List for CircuitBrokenList {
1692 fn name(&self) -> &[u8] {
1693 self.inner.name()
1694 }
1695
1696 async fn push<V>(&self, val: &V) -> Result<()>
1697 where
1698 V: Serialize + Sync + Send,
1699 {
1700 let bytes = postcard::to_stdvec(val)?;
1701 let mut svc = self.breaker.as_ref().clone();
1702 svc.call(CBStorageRequest::ListPush {
1703 list: self.inner.clone(),
1704 val: bytes,
1705 })
1706 .await
1707 .map_err(|_| {
1708 anyhow!(
1709 "storage unavailable (circuit breaker open for '{}')",
1710 self.name
1711 )
1712 })?;
1713 Ok(())
1714 }
1715
1716 async fn pushs<V>(&self, vals: Vec<V>) -> Result<()>
1717 where
1718 V: Serialize + Sync + Send,
1719 {
1720 let mut bytes_vec = Vec::with_capacity(vals.len());
1721 for v in vals {
1722 bytes_vec.push(postcard::to_stdvec(&v)?);
1723 }
1724 let mut svc = self.breaker.as_ref().clone();
1725 svc.call(CBStorageRequest::ListPushs {
1726 list: self.inner.clone(),
1727 vals: bytes_vec,
1728 })
1729 .await
1730 .map_err(|_| {
1731 anyhow!(
1732 "storage unavailable (circuit breaker open for '{}')",
1733 self.name
1734 )
1735 })?;
1736 Ok(())
1737 }
1738
1739 async fn push_limit<V>(
1740 &self,
1741 val: &V,
1742 limit: usize,
1743 pop_front_if_limited: bool,
1744 ) -> Result<Option<V>>
1745 where
1746 V: Serialize + Sync + Send + DeserializeOwned,
1747 {
1748 let bytes = postcard::to_stdvec(val)?;
1749 let mut svc = self.breaker.as_ref().clone();
1750 let resp = svc
1751 .call(CBStorageRequest::ListPushLimit {
1752 list: self.inner.clone(),
1753 val: bytes,
1754 limit,
1755 pop_front_if_limited,
1756 })
1757 .await
1758 .map_err(|_| {
1759 anyhow!(
1760 "storage unavailable (circuit breaker open for '{}')",
1761 self.name
1762 )
1763 })?;
1764 match resp {
1765 CBStorageResponse::ListPushLimit(Some(popped)) => {
1766 Ok(Some(postcard::from_bytes(&popped)?))
1767 }
1768 CBStorageResponse::ListPushLimit(None) => Ok(None),
1769 _ => Err(anyhow!("unexpected response type for list::push_limit()")),
1770 }
1771 }
1772
1773 async fn pop<V>(&self) -> Result<Option<V>>
1774 where
1775 V: DeserializeOwned + Sync + Send,
1776 {
1777 let mut svc = self.breaker.as_ref().clone();
1778 let resp = svc
1779 .call(CBStorageRequest::ListPop {
1780 list: self.inner.clone(),
1781 })
1782 .await
1783 .map_err(|_| {
1784 anyhow!(
1785 "storage unavailable (circuit breaker open for '{}')",
1786 self.name
1787 )
1788 })?;
1789 match resp {
1790 CBStorageResponse::ListPop(Some(bytes)) => Ok(Some(postcard::from_bytes(&bytes)?)),
1791 CBStorageResponse::ListPop(None) => Ok(None),
1792 _ => Err(anyhow!("unexpected response type for list::pop()")),
1793 }
1794 }
1795
1796 async fn all<V>(&self) -> Result<Vec<V>>
1797 where
1798 V: DeserializeOwned + Sync + Send,
1799 {
1800 let mut svc = self.breaker.as_ref().clone();
1801 let resp = svc
1802 .call(CBStorageRequest::ListGetAll {
1803 list: self.inner.clone(),
1804 })
1805 .await
1806 .map_err(|_| {
1807 anyhow!(
1808 "storage unavailable (circuit breaker open for '{}')",
1809 self.name
1810 )
1811 })?;
1812 match resp {
1813 CBStorageResponse::ListGetAll(vals) => vals
1814 .into_iter()
1815 .map(|bytes| postcard::from_bytes(&bytes).map_err(Into::into))
1816 .collect(),
1817 _ => Err(anyhow!("unexpected response type for list::all()")),
1818 }
1819 }
1820
1821 async fn get_index<V>(&self, idx: usize) -> Result<Option<V>>
1822 where
1823 V: DeserializeOwned + Sync + Send,
1824 {
1825 let mut svc = self.breaker.as_ref().clone();
1826 let resp = svc
1827 .call(CBStorageRequest::ListGetIndex {
1828 list: self.inner.clone(),
1829 idx,
1830 })
1831 .await
1832 .map_err(|_| {
1833 anyhow!(
1834 "storage unavailable (circuit breaker open for '{}')",
1835 self.name
1836 )
1837 })?;
1838 match resp {
1839 CBStorageResponse::ListGetIndex(Some(bytes)) => Ok(Some(postcard::from_bytes(&bytes)?)),
1840 CBStorageResponse::ListGetIndex(None) => Ok(None),
1841 _ => Err(anyhow!("unexpected response type for list::get_index()")),
1842 }
1843 }
1844
1845 async fn len(&self) -> Result<usize> {
1846 let mut svc = self.breaker.as_ref().clone();
1847 let resp = svc
1848 .call(CBStorageRequest::ListLen {
1849 list: self.inner.clone(),
1850 })
1851 .await
1852 .map_err(|_| {
1853 anyhow!(
1854 "storage unavailable (circuit breaker open for '{}')",
1855 self.name
1856 )
1857 })?;
1858 match resp {
1859 CBStorageResponse::ListLen(n) => Ok(n),
1860 _ => Err(anyhow!("unexpected response type for list::len()")),
1861 }
1862 }
1863
1864 async fn is_empty(&self) -> Result<bool> {
1865 let mut svc = self.breaker.as_ref().clone();
1866 let resp = svc
1867 .call(CBStorageRequest::ListIsEmpty {
1868 list: self.inner.clone(),
1869 })
1870 .await
1871 .map_err(|_| {
1872 anyhow!(
1873 "storage unavailable (circuit breaker open for '{}')",
1874 self.name
1875 )
1876 })?;
1877 match resp {
1878 CBStorageResponse::ListIsEmpty(b) => Ok(b),
1879 _ => Err(anyhow!("unexpected response type for list::is_empty()")),
1880 }
1881 }
1882
1883 async fn clear(&self) -> Result<()> {
1884 let mut svc = self.breaker.as_ref().clone();
1885 svc.call(CBStorageRequest::ListClear {
1886 list: self.inner.clone(),
1887 })
1888 .await
1889 .map_err(|_| {
1890 anyhow!(
1891 "storage unavailable (circuit breaker open for '{}')",
1892 self.name
1893 )
1894 })?;
1895 Ok(())
1896 }
1897
1898 async fn iter<'a, V>(
1900 &'a mut self,
1901 ) -> Result<Box<dyn AsyncIterator<Item = Result<V>> + Send + 'a>>
1902 where
1903 V: DeserializeOwned + Sync + Send + 'a + 'static,
1904 {
1905 self.inner.iter().await
1906 }
1907
1908 #[cfg(feature = "ttl")]
1909 async fn expire_at(&self, at: TimestampMillis) -> Result<bool> {
1910 let mut svc = self.breaker.as_ref().clone();
1911 let resp = svc
1912 .call(CBStorageRequest::ListExpireAt {
1913 list: self.inner.clone(),
1914 at,
1915 })
1916 .await
1917 .map_err(|_| {
1918 anyhow!(
1919 "storage unavailable (circuit breaker open for '{}')",
1920 self.name
1921 )
1922 })?;
1923 match resp {
1924 CBStorageResponse::ListExpireAt(b) => Ok(b),
1925 _ => Err(anyhow!("unexpected response type for list::expire_at()")),
1926 }
1927 }
1928
1929 #[cfg(feature = "ttl")]
1930 async fn expire(&self, dur: TimestampMillis) -> Result<bool> {
1931 let mut svc = self.breaker.as_ref().clone();
1932 let resp = svc
1933 .call(CBStorageRequest::ListExpire {
1934 list: self.inner.clone(),
1935 dur,
1936 })
1937 .await
1938 .map_err(|_| {
1939 anyhow!(
1940 "storage unavailable (circuit breaker open for '{}')",
1941 self.name
1942 )
1943 })?;
1944 match resp {
1945 CBStorageResponse::ListExpire(b) => Ok(b),
1946 _ => Err(anyhow!("unexpected response type for list::expire()")),
1947 }
1948 }
1949
1950 #[cfg(feature = "ttl")]
1951 async fn ttl(&self) -> Result<Option<TimestampMillis>> {
1952 let mut svc = self.breaker.as_ref().clone();
1953 let resp = svc
1954 .call(CBStorageRequest::ListTtl {
1955 list: self.inner.clone(),
1956 })
1957 .await
1958 .map_err(|_| {
1959 anyhow!(
1960 "storage unavailable (circuit breaker open for '{}')",
1961 self.name
1962 )
1963 })?;
1964 match resp {
1965 CBStorageResponse::ListTtl(v) => Ok(v),
1966 _ => Err(anyhow!("unexpected response type for list::ttl()")),
1967 }
1968 }
1969}
1970
1971#[cfg(test)]
1976mod cb_unit_tests {
1977 use std::pin::Pin;
1978 use std::sync::atomic::{AtomicU64, Ordering};
1979 use std::sync::Arc;
1980 use std::task::{Context, Poll};
1981 use std::time::Duration;
1982
1983 use anyhow::anyhow;
1984 use tower::Service;
1985
1986 use super::*;
1987 use crate::Result;
1988
1989 #[derive(Clone)]
1994 struct MockSvc {
1995 fail_until: u64,
1997 call_count: Arc<AtomicU64>,
1999 }
2000
2001 impl MockSvc {
2002 fn always_ok() -> Self {
2003 Self {
2004 fail_until: 0,
2005 call_count: Arc::new(AtomicU64::new(0)),
2006 }
2007 }
2008 fn fail_for(n: u64) -> Self {
2009 Self {
2010 fail_until: n,
2011 call_count: Arc::new(AtomicU64::new(0)),
2012 }
2013 }
2014 }
2015
2016 impl Service<CBStorageRequest> for MockSvc {
2017 type Response = CBStorageResponse;
2018 type Error = anyhow::Error;
2019 type Future = Pin<Box<dyn std::future::Future<Output = Result<Self::Response>> + Send>>;
2020
2021 fn poll_ready(
2022 &mut self,
2023 _cx: &mut Context<'_>,
2024 ) -> Poll<std::result::Result<(), Self::Error>> {
2025 Poll::Ready(Ok(()))
2026 }
2027
2028 fn call(&mut self, _req: CBStorageRequest) -> Self::Future {
2029 let count = self.call_count.fetch_add(1, Ordering::SeqCst);
2030 let fail_until = self.fail_until;
2031 Box::pin(async move {
2032 if count < fail_until {
2033 Err(anyhow!("mock failure (call {})", count))
2034 } else {
2035 Ok(CBStorageResponse::Insert)
2036 }
2037 })
2038 }
2039 }
2040
2041 #[derive(Clone)]
2046 struct MockMapSvc {
2047 fail_until: u64,
2048 call_count: Arc<AtomicU64>,
2049 }
2050
2051 impl MockMapSvc {
2052 fn fail_for(n: u64) -> Self {
2053 Self {
2054 fail_until: n,
2055 call_count: Arc::new(AtomicU64::new(0)),
2056 }
2057 }
2058 }
2059
2060 impl Service<CBStorageRequest> for MockMapSvc {
2061 type Response = CBStorageResponse;
2062 type Error = anyhow::Error;
2063 type Future = Pin<Box<dyn std::future::Future<Output = Result<Self::Response>> + Send>>;
2064
2065 fn poll_ready(
2066 &mut self,
2067 _cx: &mut Context<'_>,
2068 ) -> Poll<std::result::Result<(), Self::Error>> {
2069 Poll::Ready(Ok(()))
2070 }
2071
2072 fn call(&mut self, _req: CBStorageRequest) -> Self::Future {
2073 let count = self.call_count.fetch_add(1, Ordering::SeqCst);
2074 let fail_until = self.fail_until;
2075 Box::pin(async move {
2076 if count < fail_until {
2077 Err(anyhow!("mock map failure"))
2078 } else {
2079 Ok(CBStorageResponse::MapIsEmpty(true))
2080 }
2081 })
2082 }
2083 }
2084
2085 #[derive(Clone)]
2090 struct MockListSvc {
2091 fail_until: u64,
2092 call_count: Arc<AtomicU64>,
2093 }
2094
2095 impl MockListSvc {
2096 fn fail_for(n: u64) -> Self {
2097 Self {
2098 fail_until: n,
2099 call_count: Arc::new(AtomicU64::new(0)),
2100 }
2101 }
2102 }
2103
2104 impl Service<CBStorageRequest> for MockListSvc {
2105 type Response = CBStorageResponse;
2106 type Error = anyhow::Error;
2107 type Future = Pin<Box<dyn std::future::Future<Output = Result<Self::Response>> + Send>>;
2108
2109 fn poll_ready(
2110 &mut self,
2111 _cx: &mut Context<'_>,
2112 ) -> Poll<std::result::Result<(), Self::Error>> {
2113 Poll::Ready(Ok(()))
2114 }
2115
2116 fn call(&mut self, _req: CBStorageRequest) -> Self::Future {
2117 let count = self.call_count.fetch_add(1, Ordering::SeqCst);
2118 let fail_until = self.fail_until;
2119 Box::pin(async move {
2120 if count < fail_until {
2121 Err(anyhow!("mock list failure"))
2122 } else {
2123 Ok(CBStorageResponse::ListLen(0))
2124 }
2125 })
2126 }
2127 }
2128
2129 fn fast_cb_config(name: &str) -> CircuitBreakerConfig {
2135 CircuitBreakerConfig {
2136 name: name.into(),
2137 failure_rate_threshold: 0.5,
2138 window: CountBasedWindowConfig {
2139 sliding_window_size: 3,
2140 }
2141 .into(),
2142 minimum_number_of_calls: 3,
2143 wait_duration_in_open: Duration::from_millis(200),
2144 slow_call_duration_threshold: Duration::from_secs(1),
2145 slow_call_rate_threshold: 1.0,
2146 operation_timeout: None,
2147 }
2148 }
2149
2150 #[tokio::test]
2155 async fn test_ok_calls_pass_through() {
2156 let mock = MockSvc::always_ok();
2157 let cfg = fast_cb_config("pass_through");
2158 let mut cb = build_cb_inner(mock, &cfg, &cfg.name);
2159
2160 for i in 0..10 {
2161 let req = CBStorageRequest::Get {
2162 key: format!("k{}", i).into_bytes(),
2163 };
2164 let resp = cb.ready().await.unwrap().call(req).await;
2165 assert!(resp.is_ok(), "call {} should succeed", i);
2166 }
2167 }
2168
2169 #[tokio::test]
2170 async fn test_cb_propagates_inner_errors() {
2171 let mock = MockSvc::fail_for(5);
2172 let cfg = fast_cb_config("propagate_errs");
2173 let mut cb = build_cb_inner(mock, &cfg, &cfg.name);
2174
2175 let req = CBStorageRequest::Get { key: b"x".to_vec() };
2176 let resp = cb.ready().await.unwrap().call(req).await;
2177 assert!(resp.is_err(), "inner error should propagate");
2178 let err = resp.unwrap_err().to_string();
2179 assert!(err.contains("mock failure"), "unexpected error: {}", err);
2180 }
2181
2182 #[tokio::test]
2187 async fn test_cb_map_propagates_errors() {
2188 let mock = MockMapSvc::fail_for(5);
2189 let cfg = fast_cb_config("map_errs");
2190 let mut cb = build_cb_inner(mock, &cfg, &cfg.name);
2191
2192 let resp = cb
2193 .ready()
2194 .await
2195 .unwrap()
2196 .call(CBStorageRequest::DbSize)
2197 .await;
2198 assert!(resp.is_err(), "map error should propagate");
2199 }
2200
2201 #[tokio::test]
2206 async fn test_cb_list_propagates_errors() {
2207 let mock = MockListSvc::fail_for(5);
2208 let cfg = fast_cb_config("list_errs");
2209 let mut cb = build_cb_inner(mock, &cfg, &cfg.name);
2210
2211 let resp = cb
2212 .ready()
2213 .await
2214 .unwrap()
2215 .call(CBStorageRequest::DbSize)
2216 .await;
2217 assert!(resp.is_err(), "list error should propagate");
2218 }
2219}