breaker_machines 0.10.2 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.1/Cargo.toml +48 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.1/examples/basic.rs +61 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.1/src/builder.rs +232 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.1/src/bulkhead.rs +223 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.1/src/callbacks.rs +147 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.1/src/circuit.rs +1436 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.1/src/classifier.rs +177 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.1/src/errors.rs +47 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.1/src/lib.rs +62 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.1/src/storage.rs +377 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.2/Cargo.toml +48 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.2/examples/basic.rs +61 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.2/src/builder.rs +232 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.2/src/bulkhead.rs +223 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.2/src/callbacks.rs +147 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.2/src/circuit.rs +1436 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.2/src/classifier.rs +177 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.2/src/errors.rs +47 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.2/src/lib.rs +62 -0
- data/ext/breaker_machines_native/target/package/breaker-machines-0.7.2/src/storage.rs +377 -0
- data/ext/breaker_machines_native/target/release/build/clang-sys-710ac1a8148f7790/out/common.rs +355 -0
- data/ext/breaker_machines_native/target/release/build/clang-sys-710ac1a8148f7790/out/dynamic.rs +276 -0
- data/ext/breaker_machines_native/target/release/build/clang-sys-710ac1a8148f7790/out/macros.rs +49 -0
- data/ext/breaker_machines_native/target/release/build/rb-sys-9ecc9c8203d58b3a/out/bindings-0.9.117-mri-arm64-darwin24-4.0.0.rs +8974 -0
- data/lib/breaker_machines/version.rb +1 -1
- metadata +26 -2
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
//! Callback system for circuit breaker state transitions
|
|
2
|
+
|
|
3
|
+
use std::panic::{AssertUnwindSafe, catch_unwind};
|
|
4
|
+
use std::sync::Arc;
|
|
5
|
+
|
|
6
|
+
/// Type alias for circuit breaker callback functions
|
|
7
|
+
pub type CallbackFn = Arc<dyn Fn(&str) + Send + Sync>;
|
|
8
|
+
|
|
9
|
+
/// Callbacks for circuit breaker events
|
|
10
|
+
#[derive(Clone)]
|
|
11
|
+
pub struct Callbacks {
|
|
12
|
+
pub on_open: Option<CallbackFn>,
|
|
13
|
+
pub on_close: Option<CallbackFn>,
|
|
14
|
+
pub on_half_open: Option<CallbackFn>,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
impl Callbacks {
|
|
18
|
+
pub fn new() -> Self {
|
|
19
|
+
Self {
|
|
20
|
+
on_open: None,
|
|
21
|
+
on_close: None,
|
|
22
|
+
on_half_open: None,
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// Trigger the on_open callback safely, catching any panics to prevent
|
|
27
|
+
/// unwinding across FFI boundaries.
|
|
28
|
+
pub fn trigger_open(&self, circuit: &str) {
|
|
29
|
+
if let Some(ref callback) = self.on_open {
|
|
30
|
+
let cb = AssertUnwindSafe(callback);
|
|
31
|
+
let _ = catch_unwind(|| cb(circuit));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Trigger the on_close callback safely, catching any panics to prevent
|
|
36
|
+
/// unwinding across FFI boundaries.
|
|
37
|
+
pub fn trigger_close(&self, circuit: &str) {
|
|
38
|
+
if let Some(ref callback) = self.on_close {
|
|
39
|
+
let cb = AssertUnwindSafe(callback);
|
|
40
|
+
let _ = catch_unwind(|| cb(circuit));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// Trigger the on_half_open callback safely, catching any panics to prevent
|
|
45
|
+
/// unwinding across FFI boundaries.
|
|
46
|
+
pub fn trigger_half_open(&self, circuit: &str) {
|
|
47
|
+
if let Some(ref callback) = self.on_half_open {
|
|
48
|
+
let cb = AssertUnwindSafe(callback);
|
|
49
|
+
let _ = catch_unwind(|| cb(circuit));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
impl Default for Callbacks {
|
|
55
|
+
fn default() -> Self {
|
|
56
|
+
Self::new()
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
impl std::fmt::Debug for Callbacks {
|
|
61
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
62
|
+
f.debug_struct("Callbacks")
|
|
63
|
+
.field("on_open", &self.on_open.is_some())
|
|
64
|
+
.field("on_close", &self.on_close.is_some())
|
|
65
|
+
.field("on_half_open", &self.on_half_open.is_some())
|
|
66
|
+
.finish()
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#[cfg(test)]
|
|
71
|
+
mod tests {
|
|
72
|
+
use super::*;
|
|
73
|
+
use std::sync::atomic::{AtomicBool, Ordering};
|
|
74
|
+
|
|
75
|
+
#[test]
|
|
76
|
+
fn test_callback_panic_safety() {
|
|
77
|
+
// Callbacks that panic should not crash the program
|
|
78
|
+
let callbacks = Callbacks {
|
|
79
|
+
on_open: Some(Arc::new(|_| panic!("intentional panic in on_open"))),
|
|
80
|
+
on_close: Some(Arc::new(|_| panic!("intentional panic in on_close"))),
|
|
81
|
+
on_half_open: Some(Arc::new(|_| panic!("intentional panic in on_half_open"))),
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// These should not panic - the panics are caught internally
|
|
85
|
+
callbacks.trigger_open("test");
|
|
86
|
+
callbacks.trigger_close("test");
|
|
87
|
+
callbacks.trigger_half_open("test");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
#[test]
|
|
91
|
+
fn test_callback_executes_successfully() {
|
|
92
|
+
let open_called = Arc::new(AtomicBool::new(false));
|
|
93
|
+
let close_called = Arc::new(AtomicBool::new(false));
|
|
94
|
+
let half_open_called = Arc::new(AtomicBool::new(false));
|
|
95
|
+
|
|
96
|
+
let open_clone = open_called.clone();
|
|
97
|
+
let close_clone = close_called.clone();
|
|
98
|
+
let half_open_clone = half_open_called.clone();
|
|
99
|
+
|
|
100
|
+
let callbacks = Callbacks {
|
|
101
|
+
on_open: Some(Arc::new(move |_| {
|
|
102
|
+
open_clone.store(true, Ordering::SeqCst);
|
|
103
|
+
})),
|
|
104
|
+
on_close: Some(Arc::new(move |_| {
|
|
105
|
+
close_clone.store(true, Ordering::SeqCst);
|
|
106
|
+
})),
|
|
107
|
+
on_half_open: Some(Arc::new(move |_| {
|
|
108
|
+
half_open_clone.store(true, Ordering::SeqCst);
|
|
109
|
+
})),
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
callbacks.trigger_open("test");
|
|
113
|
+
callbacks.trigger_close("test");
|
|
114
|
+
callbacks.trigger_half_open("test");
|
|
115
|
+
|
|
116
|
+
assert!(
|
|
117
|
+
open_called.load(Ordering::SeqCst),
|
|
118
|
+
"on_open should be called"
|
|
119
|
+
);
|
|
120
|
+
assert!(
|
|
121
|
+
close_called.load(Ordering::SeqCst),
|
|
122
|
+
"on_close should be called"
|
|
123
|
+
);
|
|
124
|
+
assert!(
|
|
125
|
+
half_open_called.load(Ordering::SeqCst),
|
|
126
|
+
"on_half_open should be called"
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#[test]
|
|
131
|
+
fn test_callback_receives_circuit_name() {
|
|
132
|
+
let received_name = Arc::new(std::sync::Mutex::new(String::new()));
|
|
133
|
+
let name_clone = received_name.clone();
|
|
134
|
+
|
|
135
|
+
let callbacks = Callbacks {
|
|
136
|
+
on_open: Some(Arc::new(move |name| {
|
|
137
|
+
*name_clone.lock().unwrap() = name.to_string();
|
|
138
|
+
})),
|
|
139
|
+
on_close: None,
|
|
140
|
+
on_half_open: None,
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
callbacks.trigger_open("my_circuit");
|
|
144
|
+
|
|
145
|
+
assert_eq!(*received_name.lock().unwrap(), "my_circuit");
|
|
146
|
+
}
|
|
147
|
+
}
|