jaemk / self_update

Self updates for rust executables
MIT License
796 stars 69 forks source link

Not usable from async contexts #44

Open clux opened 4 years ago

clux commented 4 years ago

Hey. Was trying to use the new version to get unified reqwest 0.10 everywhere to move to async / remove dependency tree. But it seems that the blocking client interacts badly with async atm.

cargo toml:

self_update = { version = "0.13.0", features = ["archive-tar"] }
tokio = { version = "0.2.11", features = ["full"] }
reqwest = "0.10.1"

and all I have is a #[tokio::main] that a few functions down ends up calling a list on self_update::backends::github. But because, the reqwest::blocking::Client seems to spawn another tokio runtime, this just causes a panic immediately.

thread 'main' panicked at 'Cannot start a runtime from within a runtime. This happens because a function (like block_on) attempted to block the current thread while the thread is being used to drive asynchronous tasks.

Full stacktrace

``` thread 'main' panicked at 'Cannot start a runtime from within a runtime. This happens because a function (like `block_on`) attempted to block the current thread while the thread is being used to drive asynchronous tasks.', /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.11/src/runtime/enter.rs:19:5 stack backtrace: 0: 0x558ad554e274 - backtrace::backtrace::libunwind::trace::heb43798aede8bd30 at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88 1: 0x558ad554e274 - backtrace::backtrace::trace_unsynchronized::had2ba7dec4bd2732 at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/mod.rs:66 2: 0x558ad554e274 - std::sys_common::backtrace::_print_fmt::hda61f46e822731b2 at src/libstd/sys_common/backtrace.rs:84 3: 0x558ad554e274 - ::fmt::hfe37fa5de6572965 at src/libstd/sys_common/backtrace.rs:61 4: 0x558ad5577bac - core::fmt::write::h74887d18db27282c at src/libcore/fmt/mod.rs:1025 5: 0x558ad55482c7 - std::io::Write::write_fmt::h6808f3d5eceed5e5 at src/libstd/io/mod.rs:1426 6: 0x558ad5550b9e - std::sys_common::backtrace::_print::hcc0fd4b3552039ef at src/libstd/sys_common/backtrace.rs:65 7: 0x558ad5550b9e - std::sys_common::backtrace::print::h1c9c5c1c0505592d at src/libstd/sys_common/backtrace.rs:50 8: 0x558ad5550b9e - std::panicking::default_hook::{{closure}}::hefb6085c1ab83a59 at src/libstd/panicking.rs:193 9: 0x558ad5550891 - std::panicking::default_hook::h1b037d2bf0657ab3 at src/libstd/panicking.rs:210 10: 0x558ad555127b - std::panicking::rust_panic_with_hook::h787d7f532b084b9a at src/libstd/panicking.rs:471 11: 0x558ad4ffbe27 - std::panicking::begin_panic::hf6f80a6760574375 at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/panicking.rs:404 12: 0x558ad4f934dc - tokio::runtime::enter::enter::he9051ec054dcfd32 at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.11/src/runtime/enter.rs:19 13: 0x558ad4fd7ba0 - tokio::runtime::blocking::shutdown::Receiver::wait::h54c85b384d7234d9 at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.11/src/runtime/blocking/shutdown.rs:38 14: 0x558ad4fc372e - ::drop::h55575462e28eec56 at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.11/src/runtime/blocking/pool.rs:116 15: 0x558ad4925775 - core::ptr::real_drop_in_place::hb5c4378272efde28 at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libcore/ptr/mod.rs:182 16: 0x558ad491eace - core::ptr::real_drop_in_place::h64fb5188d56aaa9b at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libcore/ptr/mod.rs:182 17: 0x558ad4947df2 - reqwest::blocking::wait::enter::he8252476c7f2eab0 at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/reqwest-0.10.1/src/blocking/wait.rs:73 18: 0x558ad4945fc3 - reqwest::blocking::wait::timeout::hd66cb015ab680631 at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/reqwest-0.10.1/src/blocking/wait.rs:14 19: 0x558ad490c931 - reqwest::blocking::client::ClientHandle::new::hc530c9153f53fbba at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/reqwest-0.10.1/src/blocking/client.rs:662 20: 0x558ad490bacd - reqwest::blocking::client::ClientBuilder::build::h99c2ec740eba3deb at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/reqwest-0.10.1/src/blocking/client.rs:84 21: 0x558ad490bb81 - reqwest::blocking::client::Client::new::h49294ac019aa5ac2 at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/reqwest-0.10.1/src/blocking/client.rs:469 22: 0x558ad4375159 - self_update::backends::github::ReleaseList::fetch_releases::h79a06c8acc8f29c0 at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/self_update-0.13.0/src/backends/github.rs:159 23: 0x558ad4374c8f - self_update::backends::github::ReleaseList::fetch::h023cf19d2b8b81c5 at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/self_update-0.13.0/src/backends/github.rs:147 24: 0x558ad3b003aa - shipcat::upgrade::self_upgrade::{{closure}}::h569e7958857a5dfa at /home/clux/babylon/shipcat/shipcat_cli/src/upgrade.rs:77 25: 0x558ad39ddda8 - as core::future::future::Future>::poll::h4a29021de0d7d754 at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/future.rs:43 26: 0x558ad39d277a - std::future::poll_with_tls_context::ha5c63dde9323fd1b at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/future.rs:99 27: 0x558ad3e16b3c - shipcat::dispatch_commands::{{closure}}::h862ab6e248aeebaa at shipcat_cli/src/main.rs:539 28: 0x558ad39e84a8 - as core::future::future::Future>::poll::hc741103e33926ebc at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/future.rs:43 29: 0x558ad39d424a - std::future::poll_with_tls_context::hd217b7e226c0c204 at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/future.rs:99 30: 0x558ad3e11900 - shipcat::run::{{closure}}::h87e0a48886cfe2b5 at shipcat_cli/src/main.rs:452 31: 0x558ad39ea3b8 - as core::future::future::Future>::poll::hda07fe0bc63b7548 at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/future.rs:43 32: 0x558ad39d03ba - std::future::poll_with_tls_context::h5b5e4f50e0a8939f at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/future.rs:99 33: 0x558ad3e3e3ed - shipcat::main::{{closure}}::h4c8d52216421cce2 at shipcat_cli/src/main.rs:424 34: 0x558ad39da2ca - as core::future::future::Future>::poll::h1012b2e438abfda9 at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/future.rs:43 35: 0x558ad3f038cc - tokio::runtime::enter::Enter::block_on::h3e95c77d786ac59d at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.11/src/runtime/enter.rs:100 36: 0x558ad3f1246d - tokio::runtime::thread_pool::ThreadPool::block_on::h2968698c19f0e6e8 at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.11/src/runtime/thread_pool/mod.rs:93 37: 0x558ad3d3d5bb - tokio::runtime::Runtime::block_on::{{closure}}::hc1778ae61d231d7a at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.11/src/runtime/mod.rs:413 38: 0x558ad397d22d - tokio::runtime::context::enter::hbbd214dda6ef5038 at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.11/src/runtime/context.rs:72 39: 0x558ad3c19ba6 - tokio::runtime::handle::Handle::enter::he374b51860c2d132 at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.11/src/runtime/handle.rs:34 40: 0x558ad3d3d466 - tokio::runtime::Runtime::block_on::hefb5182b24fe2948 at /home/clux/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.11/src/runtime/mod.rs:408 41: 0x558ad3de31d9 - shipcat::main::h18a1b3b861809cb8 at shipcat_cli/src/main.rs:411 42: 0x558ad3931300 - std::rt::lang_start::{{closure}}::h1b2325711f7f7adb at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:67 43: 0x558ad5550cc3 - std::rt::lang_start_internal::{{closure}}::h0760fb8bd9f1a4c7 at src/libstd/rt.rs:52 44: 0x558ad5550cc3 - std::panicking::try::do_call::hccaa7cebf2335ab2 at src/libstd/panicking.rs:292 45: 0x558ad555afba - __rust_maybe_catch_panic at src/libpanic_unwind/lib.rs:78 46: 0x558ad55517d0 - std::panicking::try::h3ce8e2e4440720f0 at src/libstd/panicking.rs:270 47: 0x558ad55517d0 - std::panic::catch_unwind::h2a767bac361346af at src/libstd/panic.rs:394 48: 0x558ad55517d0 - std::rt::lang_start_internal::h14e7168ba039f170 at src/libstd/rt.rs:51 49: 0x558ad39312d9 - std::rt::lang_start::ha64f6a4661cac25b at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:67 50: 0x558ad3de325a - main 51: 0x7f12ed642153 - __libc_start_main 52: 0x558ad39311be - _start 53: 0x0 - ```

redrabbit commented 4 years ago

My current workaround is to use tokio::task::spawn_blocking():

In general, issuing a blocking call or performing a lot of compute in a future without yielding is not okay, as it may prevent the executor from driving other futures forward. This function runs the provided closure on a thread dedicated to blocking operations. See the CPU-bound tasks and blocking code section for more information.

https://docs.rs/tokio/0.2.22/tokio/task/fn.spawn_blocking.html

Here's a working example for the github.rs example:

diff --git a/Cargo.toml b/Cargo.toml
index 407d9f2..902402a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,6 +24,7 @@ indicatif = "0.13.0"
 quick-xml = "0.17.2"
 regex = "1.3.1"
 log = "0.4.8"
+tokio = { version = "0.2", features = ["full"] }

 [features]
 default = ["reqwest/default-tls"]
diff --git a/examples/github.rs b/examples/github.rs
index 2cffd62..4a997d5 100644
--- a/examples/github.rs
+++ b/examples/github.rs
@@ -36,9 +36,12 @@ fn run() -> Result<(), Box<dyn ::std::error::Error>> {
     Ok(())
 }

-pub fn main() {
-    if let Err(e) = run() {
-        println!("[ERROR] {}", e);
-        ::std::process::exit(1);
-    }
+#[tokio::main]
+pub async fn main() {
+    tokio::task::spawn_blocking(move || {
+        if let Err(e) = run() {
+            println!("[ERROR] {}", e);
+            ::std::process::exit(1);
+        }
+    }).await;
 }
etam commented 3 years ago

I have an idea for self_update: by default provide async functions. Provide a blocking functions in a way like reqwest does: inside a submodule and enabled by a feature.

avsaase commented 1 year ago

Another option would be to switch to an inherently synchronous http client like ureq. It's more than capable of replacing reqwest in this library and has the added benefit of using less dependencies and faster compile times. @jaemk are you open to a PR switching http clients?

jaemk commented 1 year ago

I'd be open to adding a config option to use either ureq or reqwest. I'd imagine some people might want to continue using reqwest if they are already using it elsewhere and fine with spawning a blocking task when necessary

ShayBox commented 1 year ago

Could maybe-async be used to accomplish this? I'd rather not use the spawn-blocking workaround

EDIT: This is my workaround example

#[tokio::main]
async fn main() -> Result<()> {
    tokio::task::spawn_blocking(check_for_updates).await??;

    Ok(())
}

fn check_for_updates() -> Result<Status> {
    let status = Update::configure()
        .repo_owner("ShayBox")
        .repo_name("VRC-OSC")
        .bin_name("vrc-osc")
        .show_download_progress(true)
        .current_version(CARGO_PKG_VERSION)
        .build()?
        .update()?;

    Ok(status)
}