use http::Extensions;
use reqwest::{Request, Response};
use super::{Error, Middleware, Next, Result};
use crate::error::FetchError;
pub struct CircuitBreakerMiddleware {
breaker: breaker::CircuitBreaker,
}
impl CircuitBreakerMiddleware {
pub fn new(breaker: breaker::CircuitBreaker) -> Self {
Self { breaker }
}
}
#[async_trait::async_trait]
impl Middleware for CircuitBreakerMiddleware {
async fn handle(
&self,
req: Request,
extensions: &mut Extensions,
next: Next<'_>,
) -> Result<Response> {
use breaker::State;
if self.breaker.state() == State::Open {
return Err(Error::Middleware(FetchError::CircuitOpen.into()));
}
match next.run(req, extensions).await {
Ok(response) => {
let status = response.status().as_u16();
if status == 429 || status >= 500 {
self.breaker.record_failure();
} else {
self.breaker.record_success();
}
Ok(response)
}
Err(err) => {
self.breaker.record_failure();
Err(err)
}
}
}
}