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:
timeoutbounds control operations such asstat,create_dir,rename, andpresign.io_timeoutbounds operations that open IO bodies, such asread,write, andlist, 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
impl TimeoutLayer
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new TimeoutLayer with default settings.
Sourcepub fn with_timeout(self, timeout: Duration) -> Self
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.
Sourcepub fn with_io_timeout(self, timeout: Duration) -> Self
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
impl Clone for TimeoutLayer
Source§fn clone(&self) -> TimeoutLayer
fn clone(&self) -> TimeoutLayer
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more