Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change calls to tokio::spawn to use DefaultExecutor::current().execute() instead #1566

Closed
kpcyrd opened this issue Jun 12, 2018 · 3 comments
Closed
Labels
C-feature Category: feature. This is adding a new feature. E-easy Effort: easy. A task that would be a great starting point for a new contributor.

Comments

@kpcyrd
Copy link

kpcyrd commented Jun 12, 2018

This is the http code I hacked together

pub fn get(&self, url: &str) -> Result<Response> {
    let mut request = Request::builder();
    let request = request.uri(url)
           .header("User-Agent", "my-awesome-agent/1.0")
           .body(Body::empty())?;

    let mut core = reactor::Core::new()?;
    let (parts, body) = core.run(self.client.request(request).and_then(|res| {
        println!("{:?}", res);
        let (parts, body) = res.into_parts();
        let body = body.concat2();
        (future::ok(parts), body)
    }))?;

    println!("parts: {:?}", parts);
    let body = String::from_utf8_lossy(&body);
    println!("body: {:?}", body);

    Ok(Response::from((parts, body.to_string())))
}

Here are my tests:

#[test]
#[ignore]
fn verify_200_http() {
    let client = Client::new();
    let reply = client.get("http://httpbin.org/anything").expect("request failed");
    assert_eq!(reply.status, 200);
}

#[test]
#[ignore]
fn verify_200_https() {
    let client = Client::new();
    let reply = client.get("https://httpbin.org/anything").expect("request failed");
    assert_eq!(reply.status, 200);
}

#[test]
#[ignore]
fn verify_302() {
    let client = Client::new();
    let reply = client.get("https://httpbin.org/redirect-to?url=/anything&status=302").expect("request failed");
    assert_eq!(reply.status, 302);
}

The 200 tests are working nicely, but the 302 test keeps failing with a panic from hyper/tokio. It seems this is because the url in the 302 test has no response body (Content-Lenght: 0) which may cause issues with body.concat2(). Note that this doesn't happen every time, but very often.

running 3 tests
test web::tests::verify_200_http ... ok
test web::tests::verify_200_https ... ok
thread 'tokio-runtime-worker-0' panicked at 'called `Result::unwrap()` on an `Err` value: SpawnError { is_shutdown: true }', libcore/result.rs:945:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
             at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1: std::sys_common::backtrace::print
             at libstd/sys_common/backtrace.rs:71
             at libstd/sys_common/backtrace.rs:59
   2: std::panicking::default_hook::{{closure}}
             at libstd/panicking.rs:207
   3: std::panicking::default_hook
             at libstd/panicking.rs:223
   4: std::panicking::rust_panic_with_hook
             at libstd/panicking.rs:402
   5: std::panicking::begin_panic_fmt
             at libstd/panicking.rs:349
   6: rust_begin_unwind
             at libstd/panicking.rs:325
   7: core::panicking::panic_fmt
             at libcore/panicking.rs:72
   8: core::result::unwrap_failed
             at /checkout/src/libcore/macros.rs:26
   9: <core::result::Result<T, E>>::unwrap
             at /checkout/src/libcore/result.rs:782
  10: tokio_executor::global::spawn
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-executor-0.1.2/src/global.rs:128
  11: hyper::common::exec::Exec::execute
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.12.1/src/common/exec.rs:24
  12: <hyper::client::pool::Connections<T>>::spawn_idle_interval
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.12.1/src/client/pool.rs:411
  13: <hyper::client::pool::Connections<T>>::put
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.12.1/src/client/pool.rs:369
  14: <hyper::client::pool::Pooled<T> as core::ops::drop::Drop>::drop
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.12.1/src/client/pool.rs:531
  15: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  16: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  17: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  18: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  19: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  20: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  21: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  22: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  23: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  24: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  25: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  26: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  27: <alloc::arc::Arc<T>>::drop_slow
             at /checkout/src/liballoc/arc.rs:520
  28: <alloc::arc::Arc<T> as core::ops::drop::Drop>::drop
             at /checkout/src/liballoc/arc.rs:971
  29: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  30: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  31: tokio_threadpool::worker::entry::WorkerEntry::drain_tasks
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.4/src/worker/entry.rs:204
  32: <tokio_threadpool::worker::Worker as core::ops::drop::Drop>::drop
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.4/src/worker/mod.rs:812
  33: core::ptr::drop_in_place
             at /checkout/src/libcore/ptr.rs:59
  34: tokio_threadpool::pool::Pool::spawn_thread::{{closure}}
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.4/src/pool/mod.rs:453
^C
@kpcyrd
Copy link
Author

kpcyrd commented Jun 12, 2018

It seems removing the call to body.concat2() doesn't change anything.

@seanmonstar
Copy link
Member

The panic is coming from calling tokio::spawn inside the client connection pool that is trying to spawn a timeout to remove the idle connection after a delay. tokio::spawn will panic if it called while there is no active executor.

The reason this is happening in your example is because after getting the Response, the Core is being dropped.

Note that the body.concat2() likely isn't doing what you think, since that just returns a new future, Concat2<Body>. It still needs to polled to get the final concatenated body out of it.

@seanmonstar seanmonstar changed the title Call to tokio_executor::global::spawn may fail due to empty response body Change calls to tokio::spawn to use DefaultExecutor::current().execute() instead Jun 15, 2018
@seanmonstar seanmonstar added E-easy Effort: easy. A task that would be a great starting point for a new contributor. C-feature Category: feature. This is adding a new feature. labels Jun 15, 2018
@seanmonstar
Copy link
Member

So I've repurposed this issue to track some change that could be done in hyper to make these errors clear.

If a user doesn't configure to use a custom Executor, then the implicit default is used inside common::Exec. These changes could be made:

  • Change Exec::execute to return Result<(), ::Error>, instead of panicking on error.
  • In most cases where spawning would have been critical, return the error back up to the user.
  • If the spawn wasn't critical (like the pool idle interval), log the error and ignore.
  • Add an Execute variant to hyper::Error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-feature Category: feature. This is adding a new feature. E-easy Effort: easy. A task that would be a great starting point for a new contributor.
Projects
None yet
Development

No branches or pull requests

2 participants