Repository: seanmonstar/reqwest (language: rust)

Issue:
"runtime thread cancelled: TimedOut"
I get a "runtime thread cancelled: TimedOut" on a ~~very busy machine~~ (edit: the machine is 50% idle) that is using reqwest from 16 threads. This is a new problem after I upgraded reqwest.

I appear to be able to cause the issue by `strace -fffp <pid> 2>&1 | less` and exiting the command 2 or 3 times.

relevant change: https://github.com/seanmonstar/reqwest/commit/a82232f0eef7d7b2766fa0cbb69f49f64594e6b6 (but not bisected).


Discussion / hints:
I should say that I create a `Client` and make a short get request frequently from many threads, so this timeout is frequently waited on and eventually seems to be triggered, but faster if the process is getting some of its threads paused by strace onto less.
I'm also getting this, but it's happening as soon as I try to build the client using the client builder.

```rust
        println!("Building client");
        let client = reqwest::Client::builder()
            .default_headers(headers)
            .build()
            .unwrap();
        println!("Built client: {:?}", client);
```

This code is executed in a a thread I've spawned. The second `println!` is never executed, and i just get the `runtime thread cancelled: TimedOut` panic.
I also ran into this problem under heavy load. 
The bad thing is that it just panics and crash my application:

```Rust
  wait::timeout(spawn_rx, Some(Duration::from_secs(5)))
            .expect("runtime thread cancelled")?;
```

Is it possible just return error, and not crash all world?

Fix patch:
diff --git a/src/client.rs b/src/client.rs
index 8a7a417b7..af99a33ef 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -462,14 +462,6 @@ impl ClientHandle {
             };
 
             let work = rx.for_each(move |(req, tx)| {
-                /*
-                let tx: oneshot::Sender<::Result<async_impl::Response>> = tx;
-                let task = client.execute(req)
-                    .then(move |r| {
-                        trace!("result received: {:?}", r);
-                        tx.send(r).map_err(|_| ())
-                    });
-                    */
                 let mut tx_opt: Option<oneshot::Sender<::Result<async_impl::Response>>> = Some(tx);
                 let mut res_fut = client.execute(req);
 
@@ -508,10 +500,15 @@ impl ClientHandle {
                 .expect("runtime unexpected error");
         }));
 
-        // Wait up to 5 seconds for the background thread to be spawned.
+        // Wait some seconds for the background thread to be spawned.
         // More than that and something bad is up!
-        wait::timeout(spawn_rx, Some(Duration::from_secs(5)))
-            .expect("runtime thread cancelled")?;
+        match wait::timeout(spawn_rx, Some(Duration::from_secs(10))) {
+            Ok(Ok(())) => (),
+            Ok(Err(err)) => return Err(err),
+            Err(wait::Waited::Err(_/*mpsc::Canceled*/)) |
+            Err(wait::Waited::TimedOut) => return Err(::error::runtime_startup()),
+        }
+
 
         let inner_handle = Arc::new(InnerClientHandle {
             tx: Some(tx),
diff --git a/src/error.rs b/src/error.rs
index 88e294679..6a7d86e7c 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -147,7 +147,8 @@ impl Error {
             Kind::TooManyRedirects |
             Kind::RedirectLoop |
             Kind::ClientError(_) |
-            Kind::ServerError(_) => None,
+            Kind::ServerError(_) |
+            Kind::RuntimeStartupFailure => None,
         }
     }
 
@@ -250,6 +251,7 @@ impl fmt::Display for Error {
                 f.write_str("Server Error: ")?;
                 fmt::Display::fmt(code, f)
             }
+            Kind::RuntimeStartupFailure => f.write_str("Client runtime failed to start"),
         }
     }
 }
@@ -275,6 +277,7 @@ impl StdError for Error {
             Kind::RedirectLoop => "Infinite redirect loop",
             Kind::ClientError(_) => "Client Error",
             Kind::ServerError(_) => "Server Error",
+            Kind::RuntimeStartupFailure => "Client runtime failed to start",
         }
     }
 
@@ -298,7 +301,8 @@ impl StdError for Error {
             Kind::TooManyRedirects |
             Kind::RedirectLoop |
             Kind::ClientError(_) |
-            Kind::ServerError(_) => None,
+            Kind::ServerError(_) |
+            Kind::RuntimeStartupFailure => None,
         }
     }
 }
@@ -323,6 +327,7 @@ pub(crate) enum Kind {
     RedirectLoop,
     ClientError(StatusCode),
     ServerError(StatusCode),
+    RuntimeStartupFailure,
 }
 
 
@@ -489,6 +494,10 @@ pub(crate) fn url_bad_scheme(url: Url) -> Error {
     Error::new(Kind::UrlBadScheme, Some(url))
 }
 
+pub(crate) fn runtime_startup() -> Error {
+    Error::new(Kind::RuntimeStartupFailure, None)
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;


Test patch: