use std::sync::Arc;
use axum::response::Response;
use tokio::sync::{OwnedSemaphorePermit, Semaphore};
use super::reject;
use crate::config::ConcurrencyConfig;
#[derive(Debug)]
pub(crate) struct Concurrency {
slots: Arc<Semaphore>,
}
impl Concurrency {
pub(crate) fn build(config: &ConcurrencyConfig) -> Result<Arc<Self>, String> {
if config.max_in_flight == 0 || config.max_in_flight > Semaphore::MAX_PERMITS {
return Err(format!(
"concurrency.max_in_flight must be between 1 and {}",
Semaphore::MAX_PERMITS
));
}
Ok(Arc::new(Self {
slots: Arc::new(Semaphore::new(config.max_in_flight)),
}))
}
}
impl Concurrency {
pub(super) fn take(&self) -> Option<OwnedSemaphorePermit> {
self.slots.clone().try_acquire_owned().ok()
}
pub(super) fn full() -> Response {
let mut response = reject(tonic::Code::Unavailable, "too many requests in flight");
response.headers_mut().insert(
http::header::RETRY_AFTER,
http::HeaderValue::from_static("1"),
);
response
}
}