Skip to content

Commit 3be946f

Browse files
authored
RUST-1001 Add warning about not polling futures to completion (#439)
1 parent 8c4fb66 commit 3be946f

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ This repository contains the officially supported MongoDB Rust driver, a client
2020
- [Platforms](#platforms)
2121
- [Atlas note](#atlas-note)
2222
- [Windows DNS note](#windows-dns-note)
23+
- [Warning about timeouts / cancellation](#warning-about-timeouts--cancellation)
2324
- [Bug Reporting / Feature Requests](#bug-reporting--feature-requests)
2425
- [Contributing](#contributing)
2526
- [Running the tests](#running-the-tests)
@@ -256,6 +257,30 @@ let options = ClientOptions::parse_with_resolver_config(
256257
let client = Client::with_options(options)?;
257258
```
258259

260+
## Warning about timeouts / cancellation
261+
262+
In async Rust, it is common to implement cancellation and timeouts by dropping a future after a
263+
certain period of time instead of polling it to completion. This is how
264+
[`tokio::time::timeout`](https://docs.rs/tokio/1.10.1/tokio/time/fn.timeout.html) works, for
265+
example. However, doing this with futures returned by the driver can leave the driver's internals in
266+
an inconsistent state, which may lead to unpredictable or incorrect behavior (see RUST-937 for more
267+
details). As such, it is **_highly_** recommended to poll all futures returned from the driver to
268+
completion. In order to still use timeout mechanisms like `tokio::time::timeout` with the driver,
269+
one option is to spawn tasks and time out on their
270+
[`JoinHandle`](https://docs.rs/tokio/1.10.1/tokio/task/struct.JoinHandle.html) futures instead of on
271+
the driver's futures directly. This will ensure the driver's futures will always be completely polled
272+
while also allowing the application to continue in the event of a timeout.
273+
274+
e.g.
275+
``` rust
276+
let collection = client.database("ok").collection("ok");
277+
let handle = tokio::task::spawn(async move {
278+
collection.insert_one(doc! { "x": 1 }, None).await
279+
});
280+
281+
tokio::time::timeout(Duration::from_secs(5), handle).await???;
282+
```
283+
259284
## Bug Reporting / Feature Requests
260285
To file a bug report or submit a feature request, please open a ticket on our [Jira project](https://jira.mongodb.org/browse/RUST):
261286
- Create an account and login at [jira.mongodb.org](https://jira.mongodb.org)

src/lib.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,42 @@
239239
//! }
240240
//! # }
241241
//! ```
242+
//!
243+
//! ## Warning about timeouts / cancellation
244+
//!
245+
//! In async Rust, it is common to implement cancellation and timeouts by dropping a future after a
246+
//! certain period of time instead of polling it to completion. This is how
247+
//! [`tokio::time::timeout`](https://docs.rs/tokio/1.10.1/tokio/time/fn.timeout.html) works, for
248+
//! example. However, doing this with futures returned by the driver can leave the driver's internals in
249+
//! an inconsistent state, which may lead to unpredictable or incorrect behavior (see RUST-937 for more
250+
//! details). As such, it is **_highly_** recommended to poll all futures returned from the driver to
251+
//! completion. In order to still use timeout mechanisms like `tokio::time::timeout` with the driver,
252+
//! one option is to spawn tasks and time out on their
253+
//! [`JoinHandle`](https://docs.rs/tokio/1.10.1/tokio/task/struct.JoinHandle.html) futures instead of on
254+
//! the driver's futures directly. This will ensure the driver's futures will always be completely polled
255+
//! while also allowing the application to continue in the event of a timeout.
256+
//!
257+
//! e.g.
258+
//! ``` rust
259+
//! # use std::time::Duration;
260+
//! # use mongodb::{
261+
//! # Client,
262+
//! # bson::doc,
263+
//! # };
264+
//! #
265+
//! # #[cfg(all(not(feature = "sync"), feature = "tokio-runtime"))]
266+
//! # async fn foo() -> std::result::Result<(), Box<dyn std::error::Error>> {
267+
//! #
268+
//! # let client = Client::with_uri_str("mongodb://example.com").await?;
269+
//! let collection = client.database("foo").collection("bar");
270+
//! let handle = tokio::task::spawn(async move {
271+
//! collection.insert_one(doc! { "x": 1 }, None).await
272+
//! });
273+
//!
274+
//! tokio::time::timeout(Duration::from_secs(5), handle).await???;
275+
//! # Ok(())
276+
//! # }
277+
//! ```
242278
243279
#![warn(missing_docs)]
244280
#![warn(missing_crate_level_docs)]

0 commit comments

Comments
 (0)