Skip to main content

TimeoutLayer

Struct TimeoutLayer 

Source
pub struct TimeoutLayer { /* private fields */ }
Expand description

TimeoutLayer adds deadlines to operations so slow or stalled work cannot hang indefinitely.

For example, a dead connection could stall a database query. TimeoutLayer interrupts the operation and returns an error that users can retry or report.

§Notes

TimeoutLayer applies two timeout budgets:

  • timeout bounds control operations such as stat, create_dir, rename, and presign.
  • io_timeout bounds operations that open IO bodies, such as read, write, and list, and every method call on returned readers, writers, listers, deleters, and copiers.

§Default

  • timeout: 60 seconds
  • io_timeout: 10 seconds

§Cancellation Safety

TimeoutLayer enforces deadlines by dropping the in-flight future when a timeout is reached. This can break lower layers that rely on a future being resolved to restore internal state.

For example, while using TimeoutLayer with RetryLayer at the same time, please make sure timeout layer is added before retry layer.

let op = Operator::new(services::Memory::default())?
    // This is fine: each retry attempt is timed out.
    .layer(TimeoutLayer::default().with_io_timeout(Duration::from_nanos(1)))
    .layer(RetryLayer::default())
    // This is wrong: timeout can drop RetryLayer's future before it restores body state.
    .layer(TimeoutLayer::default().with_io_timeout(Duration::from_nanos(1)));

§Examples

The following example creates a timeout layer with a 10-second timeout for control operations and a 3-second timeout for IO operations.

let _ = Operator::new(services::Memory::default())?
    .layer(
        TimeoutLayer::default()
            .with_timeout(Duration::from_secs(10))
            .with_io_timeout(Duration::from_secs(3)),
    );

§Implementation Notes

TimeoutLayer uses tokio::time::timeout to bound service calls and IO body methods. It also supplies an executor timeout so concurrent block write and copy tasks can fail instead of waiting forever.

This introduces a small amount of overhead for IO operations, but it is needed to implement timeouts correctly. OpenDAL used to implement this as a zero-cost deadline check that only stored an Instant and compared it with the current time. However, that approach does not work for all cases.

For example, a user’s TCP connection could enter the Busy ESTAB state. In this state, the connection emits no IO events, so the runtime never polls the future again. The future hangs until Linux closes the connection after it reaches the net.ipv4.tcp_retries2 limit.

Implementations§

Source§

impl TimeoutLayer

Source

pub fn new() -> Self

Create a new TimeoutLayer with default settings.

Source

pub fn with_timeout(self, timeout: Duration) -> Self

Set the timeout for control operations.

This timeout is for all non-io operations like stat, delete.

Source

pub fn with_io_timeout(self, timeout: Duration) -> Self

Set the timeout for IO operations and body methods.

This timeout is for all io operations like read, Reader::read and Writer::write.

Trait Implementations§

Source§

impl Clone for TimeoutLayer

Source§

fn clone(&self) -> TimeoutLayer

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for TimeoutLayer

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for TimeoutLayer

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Layer for TimeoutLayer

Source§

fn apply_service(&self, inner: Servicer) -> Servicer

Intercept the operation service stack. Read more
Source§

fn apply_context( &self, _srv: Servicer, inner: OperationContext, ) -> OperationContext

Intercept the operation context (HTTP transport and executor). Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> MaybeSend for T
where T: Send,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.