load_balancer/
fault_tolerant.rs1use crate::LoadBalancer;
2use std::sync::atomic::Ordering::{Acquire, Release};
3use std::{
4 future::Future,
5 sync::{Arc, atomic::AtomicU64},
6 time::{Duration, Instant},
7};
8use tokio::{
9 spawn,
10 sync::{Mutex, RwLock},
11 task::{JoinHandle, yield_now},
12 time::sleep,
13};
14
15pub struct Entry<T>
18where
19 T: Send + Sync + Clone + 'static,
20{
21 pub max_count: u64,
23 pub max_error_count: u64,
25 pub count: AtomicU64,
27 pub error_count: AtomicU64,
29 pub value: T,
31}
32
33impl<T> Entry<T>
34where
35 T: Send + Sync + Clone + 'static,
36{
37 pub fn reset(&self) {
39 self.count.store(0, Release);
40 self.error_count.store(0, Release);
41 }
42
43 pub fn disable(&self) {
45 self.error_count.store(self.max_error_count, Release);
46 }
47}
48
49impl<T> Clone for Entry<T>
50where
51 T: Send + Sync + Clone + 'static,
52{
53 fn clone(&self) -> Self {
54 Self {
55 max_count: self.max_count.clone(),
56 max_error_count: self.max_error_count.clone(),
57 count: self.count.load(Acquire).into(),
58 error_count: self.error_count.load(Acquire).into(),
59 value: self.value.clone(),
60 }
61 }
62}
63
64pub struct Inner<T>
66where
67 T: Send + Sync + Clone + 'static,
68{
69 pub entries: RwLock<Vec<Entry<T>>>,
71 pub timer: Mutex<Option<JoinHandle<()>>>,
73 pub interval: RwLock<Duration>,
75 pub next_reset: RwLock<Instant>,
77}
78
79#[derive(Clone)]
84pub struct FaultTolerant<T>
85where
86 T: Send + Sync + Clone + 'static,
87{
88 inner: Arc<Inner<T>>,
89}
90
91impl<T> FaultTolerant<T>
92where
93 T: Send + Sync + Clone + 'static,
94{
95 pub fn new(entries: Vec<(u64, u64, T)>) -> Self {
104 Self::new_interval(entries, Duration::from_secs(1))
105 }
106
107 pub fn new_interval(entries: Vec<(u64, u64, T)>, interval: Duration) -> Self {
118 Self {
119 inner: Arc::new(Inner {
120 entries: entries
121 .into_iter()
122 .map(|(max_count, max_error_count, value)| Entry {
123 max_count,
124 max_error_count,
125 value,
126 count: 0.into(),
127 error_count: 0.into(),
128 })
129 .collect::<Vec<_>>()
130 .into(),
131 timer: Mutex::new(None),
132 interval: interval.into(),
133 next_reset: RwLock::new(Instant::now() + interval),
134 }),
135 }
136 }
137
138 pub async fn update<F, R>(&self, handler: F) -> anyhow::Result<()>
140 where
141 F: Fn(Arc<Inner<T>>) -> R,
142 R: Future<Output = anyhow::Result<()>>,
143 {
144 handler(self.inner.clone()).await
145 }
146
147 pub async fn update_timer<F, R>(
153 &self,
154 handler: F,
155 interval: Duration,
156 ) -> anyhow::Result<JoinHandle<()>>
157 where
158 F: Fn(Arc<Inner<T>>) -> R + Send + Sync + 'static,
159 R: Future<Output = anyhow::Result<()>> + Send,
160 {
161 handler(self.inner.clone()).await?;
162
163 let inner = self.inner.clone();
164
165 Ok(spawn(async move {
166 loop {
167 sleep(interval).await;
168 let _ = handler(inner.clone()).await;
169 }
170 }))
171 }
172
173 pub async fn alloc_skip(&self, skip_index: usize) -> (usize, T) {
175 loop {
176 if let Some(v) = self.try_alloc_skip(skip_index) {
177 return v;
178 }
179
180 let now = Instant::now();
181
182 let next = *self.inner.next_reset.read().await;
183
184 let remaining = if now < next {
185 next - now
186 } else {
187 Duration::ZERO
188 };
189
190 if remaining > Duration::ZERO {
191 sleep(remaining).await;
192 } else {
193 yield_now().await;
194 }
195 }
196 }
197
198 pub fn try_alloc_skip(&self, skip_index: usize) -> Option<(usize, T)> {
200 if let Ok(mut timer_guard) = self.inner.timer.try_lock() {
201 if timer_guard.is_none() {
202 let this = self.inner.clone();
203
204 *timer_guard = Some(spawn(async move {
205 let mut interval = *this.interval.read().await;
206
207 *this.next_reset.write().await = Instant::now() + interval;
208
209 loop {
210 sleep(match this.interval.try_read() {
211 Ok(v) => {
212 interval = *v;
213 interval
214 }
215 Err(_) => interval,
216 })
217 .await;
218
219 let now = Instant::now();
220
221 let entries = this.entries.read().await;
222
223 for entry in entries.iter() {
224 entry.count.store(0, Release);
225 }
226
227 *this.next_reset.write().await = now + interval;
228 }
229 }));
230 }
231 }
232
233 if let Ok(entries) = self.inner.entries.try_read() {
234 let mut skip_count = 0;
235
236 for (i, entry) in entries.iter().enumerate() {
237 if i == skip_index {
238 continue;
239 }
240
241 if entry.max_error_count != 0
242 && entry.error_count.load(Acquire) >= entry.max_error_count
243 {
244 skip_count += 1;
245 continue;
246 }
247
248 let count = entry.count.load(Acquire);
249
250 if entry.max_count == 0
251 || (count < entry.max_count
252 && entry
253 .count
254 .compare_exchange(count, count + 1, Release, Acquire)
255 .is_ok())
256 {
257 return Some((i, entry.value.clone()));
258 }
259 }
260
261 if skip_count == entries.len() {
262 return None;
263 }
264 }
265
266 None
267 }
268
269 pub fn success(&self, index: usize) {
275 if let Ok(entries) = self.inner.entries.try_read() {
276 if let Some(entry) = entries.get(index) {
277 let current = entry.error_count.load(Acquire);
278
279 if current != 0 {
280 let _ =
281 entry
282 .error_count
283 .compare_exchange(current, current - 1, Release, Acquire);
284 }
285 }
286 }
287 }
288
289 pub fn failure(&self, index: usize) {
295 if let Ok(entries) = self.inner.entries.try_read() {
296 if let Some(entry) = entries.get(index) {
297 entry.error_count.fetch_add(1, Release);
298 }
299 }
300 }
301}
302
303impl<T> LoadBalancer<T> for FaultTolerant<T>
304where
305 T: Clone + Send + Sync + 'static,
306{
307 fn alloc(&self) -> impl Future<Output = T> + Send {
309 async move { self.alloc_skip(usize::MAX).await.1 }
310 }
311
312 fn try_alloc(&self) -> Option<T> {
314 self.try_alloc_skip(usize::MAX).map(|v| v.1)
315 }
316}