pub struct TimeoutLayer { /* private fields */ }Expand description
Add timeouts to operations to avoid slow or unexpectedly hanging work.
For example, a dead connection could hang a database SQL query. TimeoutLayer
will break this connection and return an error so users can handle it by
retrying or reporting it.
§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, no IO event will be emitted, so the runtime will never poll the future again. From the application side, this future hangs until the connection is closed after reaching the Linux 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