breaker_machines 0.5.0 → 0.6.0

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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/ext/breaker_machines_native/Cargo.toml +8 -0
  3. data/ext/breaker_machines_native/core/Cargo.toml +18 -0
  4. data/ext/breaker_machines_native/core/examples/basic.rs +61 -0
  5. data/ext/breaker_machines_native/core/src/builder.rs +232 -0
  6. data/ext/breaker_machines_native/core/src/bulkhead.rs +223 -0
  7. data/ext/breaker_machines_native/core/src/callbacks.rs +58 -0
  8. data/ext/breaker_machines_native/core/src/circuit.rs +1156 -0
  9. data/ext/breaker_machines_native/core/src/classifier.rs +177 -0
  10. data/ext/breaker_machines_native/core/src/errors.rs +47 -0
  11. data/ext/breaker_machines_native/core/src/lib.rs +62 -0
  12. data/ext/breaker_machines_native/core/src/storage.rs +377 -0
  13. data/ext/breaker_machines_native/extconf.rb +40 -0
  14. data/ext/breaker_machines_native/ffi/Cargo.toml +16 -0
  15. data/ext/breaker_machines_native/ffi/src/lib.rs +218 -0
  16. data/ext/breaker_machines_native/target/debug/build/clang-sys-d961dfabd5f43fba/out/common.rs +355 -0
  17. data/ext/breaker_machines_native/target/debug/build/clang-sys-d961dfabd5f43fba/out/dynamic.rs +276 -0
  18. data/ext/breaker_machines_native/target/debug/build/clang-sys-d961dfabd5f43fba/out/macros.rs +49 -0
  19. data/ext/breaker_machines_native/target/debug/build/rb-sys-2bb7281aac8faec8/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs +8936 -0
  20. data/ext/breaker_machines_native/target/debug/build/rb-sys-54cb99ea6aeab8bc/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs +8936 -0
  21. data/ext/breaker_machines_native/target/debug/build/rb-sys-9e64a270c6421e93/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs +8936 -0
  22. data/ext/breaker_machines_native/target/debug/build/rb-sys-e627030114d3fc19/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs +8936 -0
  23. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/Cargo.toml +48 -0
  24. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/examples/basic.rs +61 -0
  25. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/builder.rs +154 -0
  26. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/callbacks.rs +55 -0
  27. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/circuit.rs +607 -0
  28. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/errors.rs +38 -0
  29. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/lib.rs +58 -0
  30. data/ext/breaker_machines_native/target/package/breaker-machines-0.1.0/src/storage.rs +377 -0
  31. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/Cargo.toml +48 -0
  32. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/examples/basic.rs +61 -0
  33. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/builder.rs +173 -0
  34. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/callbacks.rs +55 -0
  35. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/circuit.rs +855 -0
  36. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/errors.rs +38 -0
  37. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/lib.rs +58 -0
  38. data/ext/breaker_machines_native/target/package/breaker-machines-0.2.0/src/storage.rs +377 -0
  39. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/Cargo.toml +48 -0
  40. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/examples/basic.rs +61 -0
  41. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/builder.rs +154 -0
  42. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/callbacks.rs +55 -0
  43. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/circuit.rs +607 -0
  44. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/errors.rs +38 -0
  45. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/lib.rs +58 -0
  46. data/ext/breaker_machines_native/target/package/breaker-machines-0.5.0/src/storage.rs +377 -0
  47. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/Cargo.toml +48 -0
  48. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/examples/basic.rs +61 -0
  49. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/builder.rs +232 -0
  50. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/bulkhead.rs +223 -0
  51. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/callbacks.rs +58 -0
  52. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/circuit.rs +1156 -0
  53. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/classifier.rs +177 -0
  54. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/errors.rs +47 -0
  55. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/lib.rs +62 -0
  56. data/ext/breaker_machines_native/target/package/breaker-machines-0.6.0/src/storage.rs +377 -0
  57. data/ext/breaker_machines_native/target/release/build/clang-sys-ef8ad8b846ac8b75/out/common.rs +355 -0
  58. data/ext/breaker_machines_native/target/release/build/clang-sys-ef8ad8b846ac8b75/out/dynamic.rs +276 -0
  59. data/ext/breaker_machines_native/target/release/build/clang-sys-ef8ad8b846ac8b75/out/macros.rs +49 -0
  60. data/ext/breaker_machines_native/target/release/build/rb-sys-064bf9961dd17810/out/bindings-0.9.117-mri-arm64-darwin24-3.4.7.rs +8936 -0
  61. data/lib/breaker_machines/circuit/async_state_management.rb +1 -1
  62. data/lib/breaker_machines/circuit/base.rb +2 -1
  63. data/lib/breaker_machines/circuit/coordinated_state_management.rb +3 -3
  64. data/lib/breaker_machines/circuit/native.rb +127 -0
  65. data/lib/breaker_machines/circuit/state_callbacks.rb +17 -5
  66. data/lib/breaker_machines/circuit/state_management.rb +1 -1
  67. data/lib/breaker_machines/native_extension.rb +36 -0
  68. data/lib/breaker_machines/native_speedup.rb +6 -0
  69. data/lib/breaker_machines/storage/bucket_memory.rb +4 -1
  70. data/lib/breaker_machines/storage/memory.rb +4 -1
  71. data/lib/breaker_machines/storage/native.rb +90 -0
  72. data/lib/breaker_machines/version.rb +1 -1
  73. data/lib/breaker_machines.rb +98 -11
  74. data/lib/breaker_machines_native/breaker_machines_native.bundle +0 -0
  75. data/sig/breaker_machines.rbs +20 -8
  76. metadata +99 -6
@@ -0,0 +1,154 @@
1
+ //! Builder API for ergonomic circuit breaker configuration
2
+
3
+ use crate::{
4
+ callbacks::Callbacks,
5
+ circuit::{CircuitBreaker, CircuitContext, Config},
6
+ MemoryStorage, StorageBackend,
7
+ };
8
+ use std::sync::Arc;
9
+
10
+ /// Builder for creating circuit breakers with fluent API
11
+ pub struct CircuitBuilder {
12
+ name: String,
13
+ config: Config,
14
+ storage: Option<Arc<dyn StorageBackend>>,
15
+ callbacks: Callbacks,
16
+ }
17
+
18
+ impl CircuitBuilder {
19
+ /// Create a new builder for a circuit with the given name
20
+ pub fn new(name: impl Into<String>) -> Self {
21
+ Self {
22
+ name: name.into(),
23
+ config: Config::default(),
24
+ storage: None,
25
+ callbacks: Callbacks::new(),
26
+ }
27
+ }
28
+
29
+ /// Set the failure threshold (number of failures to open circuit)
30
+ pub fn failure_threshold(mut self, threshold: usize) -> Self {
31
+ self.config.failure_threshold = threshold;
32
+ self
33
+ }
34
+
35
+ /// Set the failure window in seconds
36
+ pub fn failure_window_secs(mut self, seconds: f64) -> Self {
37
+ self.config.failure_window_secs = seconds;
38
+ self
39
+ }
40
+
41
+ /// Set the half-open timeout in seconds
42
+ pub fn half_open_timeout_secs(mut self, seconds: f64) -> Self {
43
+ self.config.half_open_timeout_secs = seconds;
44
+ self
45
+ }
46
+
47
+ /// Set the success threshold (successes needed to close from half-open)
48
+ pub fn success_threshold(mut self, threshold: usize) -> Self {
49
+ self.config.success_threshold = threshold;
50
+ self
51
+ }
52
+
53
+ /// Set the jitter factor (0.0 = no jitter, 1.0 = full jitter)
54
+ /// Uses chrono-machines formula: timeout * (1 - jitter + rand * jitter)
55
+ pub fn jitter_factor(mut self, factor: f64) -> Self {
56
+ self.config.jitter_factor = factor;
57
+ self
58
+ }
59
+
60
+ /// Set custom storage backend
61
+ pub fn storage(mut self, storage: Arc<dyn StorageBackend>) -> Self {
62
+ self.storage = Some(storage);
63
+ self
64
+ }
65
+
66
+ /// Set callback for when circuit opens
67
+ pub fn on_open<F>(mut self, f: F) -> Self
68
+ where
69
+ F: Fn(&str) + Send + Sync + 'static,
70
+ {
71
+ self.callbacks.on_open = Some(Arc::new(f));
72
+ self
73
+ }
74
+
75
+ /// Set callback for when circuit closes
76
+ pub fn on_close<F>(mut self, f: F) -> Self
77
+ where
78
+ F: Fn(&str) + Send + Sync + 'static,
79
+ {
80
+ self.callbacks.on_close = Some(Arc::new(f));
81
+ self
82
+ }
83
+
84
+ /// Set callback for when circuit enters half-open
85
+ pub fn on_half_open<F>(mut self, f: F) -> Self
86
+ where
87
+ F: Fn(&str) + Send + Sync + 'static,
88
+ {
89
+ self.callbacks.on_half_open = Some(Arc::new(f));
90
+ self
91
+ }
92
+
93
+ /// Build the circuit breaker
94
+ pub fn build(self) -> CircuitBreaker {
95
+ let storage = self
96
+ .storage
97
+ .unwrap_or_else(|| Arc::new(MemoryStorage::new()));
98
+
99
+ let context = CircuitContext {
100
+ name: self.name,
101
+ config: self.config,
102
+ storage,
103
+ };
104
+
105
+ CircuitBreaker::with_context_and_callbacks(context, self.callbacks)
106
+ }
107
+ }
108
+
109
+ #[cfg(test)]
110
+ mod tests {
111
+ use super::*;
112
+
113
+ #[test]
114
+ fn test_builder_defaults() {
115
+ let circuit = CircuitBuilder::new("test").build();
116
+
117
+ assert_eq!(circuit.state_name(), "Closed");
118
+ assert!(circuit.is_closed());
119
+ }
120
+
121
+ #[test]
122
+ fn test_builder_custom_config() {
123
+ let circuit = CircuitBuilder::new("test")
124
+ .failure_threshold(10)
125
+ .failure_window_secs(120.0)
126
+ .half_open_timeout_secs(60.0)
127
+ .success_threshold(3)
128
+ .build();
129
+
130
+ assert!(circuit.is_closed());
131
+ }
132
+
133
+ #[test]
134
+ fn test_builder_with_callbacks() {
135
+ use std::sync::atomic::{AtomicBool, Ordering};
136
+
137
+ let opened = Arc::new(AtomicBool::new(false));
138
+ let opened_clone = opened.clone();
139
+
140
+ let mut circuit = CircuitBuilder::new("test")
141
+ .failure_threshold(2)
142
+ .on_open(move |_name| {
143
+ opened_clone.store(true, Ordering::SeqCst);
144
+ })
145
+ .build();
146
+
147
+ // Trigger failures to open circuit
148
+ let _ = circuit.call(|| Err::<(), _>("error 1"));
149
+ let _ = circuit.call(|| Err::<(), _>("error 2"));
150
+
151
+ // Callback should have been triggered
152
+ assert!(opened.load(Ordering::SeqCst));
153
+ }
154
+ }
@@ -0,0 +1,55 @@
1
+ //! Callback system for circuit breaker state transitions
2
+
3
+ use std::sync::Arc;
4
+
5
+ /// Callbacks for circuit breaker events
6
+ #[derive(Clone)]
7
+ pub struct Callbacks {
8
+ pub on_open: Option<Arc<dyn Fn(&str) + Send + Sync>>,
9
+ pub on_close: Option<Arc<dyn Fn(&str) + Send + Sync>>,
10
+ pub on_half_open: Option<Arc<dyn Fn(&str) + Send + Sync>>,
11
+ }
12
+
13
+ impl Callbacks {
14
+ pub fn new() -> Self {
15
+ Self {
16
+ on_open: None,
17
+ on_close: None,
18
+ on_half_open: None,
19
+ }
20
+ }
21
+
22
+ pub fn trigger_open(&self, circuit: &str) {
23
+ if let Some(ref callback) = self.on_open {
24
+ callback(circuit);
25
+ }
26
+ }
27
+
28
+ pub fn trigger_close(&self, circuit: &str) {
29
+ if let Some(ref callback) = self.on_close {
30
+ callback(circuit);
31
+ }
32
+ }
33
+
34
+ pub fn trigger_half_open(&self, circuit: &str) {
35
+ if let Some(ref callback) = self.on_half_open {
36
+ callback(circuit);
37
+ }
38
+ }
39
+ }
40
+
41
+ impl Default for Callbacks {
42
+ fn default() -> Self {
43
+ Self::new()
44
+ }
45
+ }
46
+
47
+ impl std::fmt::Debug for Callbacks {
48
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49
+ f.debug_struct("Callbacks")
50
+ .field("on_open", &self.on_open.is_some())
51
+ .field("on_close", &self.on_close.is_some())
52
+ .field("on_half_open", &self.on_half_open.is_some())
53
+ .finish()
54
+ }
55
+ }