use std::time::Duration;
#[derive(Clone, Debug, Default)]
pub struct Timeouts {
pub connect: Option<Duration>,
pub ttfb: Option<Duration>,
pub read_idle: Option<Duration>,
pub write_idle: Option<Duration>,
pub total: Option<Duration>,
pub pool_acquire: Option<Duration>,
}
impl Timeouts {
pub fn new() -> Self {
Self::default()
}
pub fn api_defaults() -> Self {
Self {
connect: Some(Duration::from_secs(10)),
ttfb: Some(Duration::from_secs(30)),
read_idle: Some(Duration::from_secs(30)),
write_idle: Some(Duration::from_secs(30)),
total: Some(Duration::from_secs(120)),
pool_acquire: Some(Duration::from_secs(5)),
}
}
pub fn streaming_defaults() -> Self {
Self {
connect: Some(Duration::from_secs(10)),
ttfb: Some(Duration::from_secs(30)),
read_idle: Some(Duration::from_secs(120)),
write_idle: Some(Duration::from_secs(30)),
total: None, pool_acquire: Some(Duration::from_secs(5)),
}
}
pub fn connect(mut self, timeout: Duration) -> Self {
self.connect = Some(timeout);
self
}
pub fn ttfb(mut self, timeout: Duration) -> Self {
self.ttfb = Some(timeout);
self
}
pub fn read_idle(mut self, timeout: Duration) -> Self {
self.read_idle = Some(timeout);
self
}
pub fn write_idle(mut self, timeout: Duration) -> Self {
self.write_idle = Some(timeout);
self
}
pub fn total(mut self, timeout: Duration) -> Self {
self.total = Some(timeout);
self
}
pub fn pool_acquire(mut self, timeout: Duration) -> Self {
self.pool_acquire = Some(timeout);
self
}
pub fn no_connect_timeout(mut self) -> Self {
self.connect = None;
self
}
pub fn no_ttfb_timeout(mut self) -> Self {
self.ttfb = None;
self
}
pub fn no_read_idle_timeout(mut self) -> Self {
self.read_idle = None;
self
}
pub fn no_write_idle_timeout(mut self) -> Self {
self.write_idle = None;
self
}
pub fn no_total_timeout(mut self) -> Self {
self.total = None;
self
}
pub fn no_pool_acquire_timeout(mut self) -> Self {
self.pool_acquire = None;
self
}
}
pub async fn recv_with_idle_timeout<T>(
rx: &mut tokio::sync::mpsc::Receiver<T>,
idle: Duration,
) -> crate::Result<Option<T>> {
tokio::select! {
biased;
v = rx.recv() => Ok(v),
_ = tokio::time::sleep(idle) => Err(crate::Error::ReadIdleTimeout(idle)),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_api_defaults() {
let t = Timeouts::api_defaults();
assert_eq!(t.connect, Some(Duration::from_secs(10)));
assert_eq!(t.ttfb, Some(Duration::from_secs(30)));
assert_eq!(t.read_idle, Some(Duration::from_secs(30)));
assert_eq!(t.total, Some(Duration::from_secs(120)));
}
#[test]
fn test_streaming_defaults() {
let t = Timeouts::streaming_defaults();
assert_eq!(t.connect, Some(Duration::from_secs(10)));
assert_eq!(t.ttfb, Some(Duration::from_secs(30)));
assert_eq!(t.read_idle, Some(Duration::from_secs(120)));
assert_eq!(t.total, None); }
#[test]
fn test_builder_pattern() {
let t = Timeouts::new()
.connect(Duration::from_secs(5))
.ttfb(Duration::from_secs(15))
.read_idle(Duration::from_secs(60));
assert_eq!(t.connect, Some(Duration::from_secs(5)));
assert_eq!(t.ttfb, Some(Duration::from_secs(15)));
assert_eq!(t.read_idle, Some(Duration::from_secs(60)));
assert_eq!(t.total, None);
}
}