Skip to main content

tower_bulkhead/
config.rs

1//! Configuration for the bulkhead pattern.
2
3use crate::events::BulkheadEvent;
4use std::time::Duration;
5use tower_resilience_core::events::{EventListeners, FnListener};
6
7/// Configuration for the bulkhead pattern.
8#[derive(Clone)]
9pub struct BulkheadConfig {
10    /// Maximum number of concurrent calls allowed.
11    pub(crate) max_concurrent_calls: usize,
12    /// Maximum time to wait for a permit.
13    pub(crate) max_wait_duration: Option<Duration>,
14    /// Name of this bulkhead instance.
15    pub(crate) name: String,
16    /// Event listeners.
17    pub(crate) event_listeners: EventListeners<BulkheadEvent>,
18}
19
20impl BulkheadConfig {
21    /// Creates a new configuration builder.
22    pub fn builder() -> BulkheadConfigBuilder {
23        BulkheadConfigBuilder::new()
24    }
25}
26
27/// Builder for bulkhead configuration.
28pub struct BulkheadConfigBuilder {
29    max_concurrent_calls: usize,
30    max_wait_duration: Option<Duration>,
31    name: String,
32    event_listeners: EventListeners<BulkheadEvent>,
33}
34
35impl BulkheadConfigBuilder {
36    /// Creates a new builder with default values.
37    pub fn new() -> Self {
38        Self {
39            max_concurrent_calls: 25,
40            max_wait_duration: None,
41            name: "bulkhead".to_string(),
42            event_listeners: EventListeners::new(),
43        }
44    }
45
46    /// Sets the maximum number of concurrent calls.
47    ///
48    /// Default: 25
49    pub fn max_concurrent_calls(mut self, max: usize) -> Self {
50        self.max_concurrent_calls = max;
51        self
52    }
53
54    /// Sets the maximum time to wait for a permit.
55    ///
56    /// If `None`, calls will wait indefinitely.
57    /// Default: None
58    pub fn max_wait_duration(mut self, duration: Option<Duration>) -> Self {
59        self.max_wait_duration = duration;
60        self
61    }
62
63    /// Sets the name of this bulkhead instance.
64    ///
65    /// Default: "bulkhead"
66    pub fn name(mut self, name: impl Into<String>) -> Self {
67        self.name = name.into();
68        self
69    }
70
71    /// Registers a callback for when a call is permitted.
72    pub fn on_call_permitted<F>(mut self, f: F) -> Self
73    where
74        F: Fn(usize) + Send + Sync + 'static,
75    {
76        self.event_listeners.add(FnListener::new(move |event| {
77            if let BulkheadEvent::CallPermitted {
78                concurrent_calls, ..
79            } = event
80            {
81                f(*concurrent_calls);
82            }
83        }));
84        self
85    }
86
87    /// Registers a callback for when a call is rejected.
88    pub fn on_call_rejected<F>(mut self, f: F) -> Self
89    where
90        F: Fn(usize) + Send + Sync + 'static,
91    {
92        self.event_listeners.add(FnListener::new(move |event| {
93            if let BulkheadEvent::CallRejected {
94                max_concurrent_calls,
95                ..
96            } = event
97            {
98                f(*max_concurrent_calls);
99            }
100        }));
101        self
102    }
103
104    /// Registers a callback for when a call finishes successfully.
105    pub fn on_call_finished<F>(mut self, f: F) -> Self
106    where
107        F: Fn(Duration) + Send + Sync + 'static,
108    {
109        self.event_listeners.add(FnListener::new(move |event| {
110            if let BulkheadEvent::CallFinished { duration, .. } = event {
111                f(*duration);
112            }
113        }));
114        self
115    }
116
117    /// Registers a callback for when a call fails.
118    pub fn on_call_failed<F>(mut self, f: F) -> Self
119    where
120        F: Fn(Duration) + Send + Sync + 'static,
121    {
122        self.event_listeners.add(FnListener::new(move |event| {
123            if let BulkheadEvent::CallFailed { duration, .. } = event {
124                f(*duration);
125            }
126        }));
127        self
128    }
129
130    /// Builds the configuration and returns a BulkheadLayer.
131    pub fn build(self) -> crate::layer::BulkheadLayer {
132        let config = BulkheadConfig {
133            max_concurrent_calls: self.max_concurrent_calls,
134            max_wait_duration: self.max_wait_duration,
135            name: self.name,
136            event_listeners: self.event_listeners,
137        };
138        crate::layer::BulkheadLayer::new(config)
139    }
140}
141
142impl Default for BulkheadConfigBuilder {
143    fn default() -> Self {
144        Self::new()
145    }
146}