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

backoff::future::retry doesn't work on wasm32-unknown-unknown with tokio because of reliance on TokioSleeper and time #61

Open
leighmcculloch opened this issue Nov 15, 2022 · 2 comments

Comments

@leighmcculloch
Copy link

leighmcculloch commented Nov 15, 2022

The backoff::future::retry works well on wasm32-unknown-unknown with tokio as long as there is never an error that triggers the backoff. Once a backoff is triggered the TokioSleeper is used and tokio::time is used.

backoff/src/future.rs

Lines 218 to 224 in 587e2da

struct TokioSleeper;
#[cfg(feature = "tokio")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
impl Sleeper for TokioSleeper {
type Sleep = ::tokio_1::time::Sleep;
fn sleep(&self, dur: Duration) -> Self::Sleep {
::tokio_1::time::sleep(dur)

The problem with this is that on wasm32-unknown-unknown with no time source, a panic is caused by this attempt to sleep with tokio. This is because tokio only uses the std time which isn't implemented. The following panic will be seen:

panicked at 'time not implemented on this platform', library/std/src/sys/wasm/../unsupported/time.rs:13:9

Stack:

<?>.wasm-function[console_error_panic_hook::Error::new::hf6b67bbb1aa769d8]@[wasm code]
<?>.wasm-function[console_error_panic_hook::hook_impl::h1826ea7fdfe0e730]@[wasm code]
<?>.wasm-function[console_error_panic_hook::hook::ha2b94ff4b371fbc5]@[wasm code]
<?>.wasm-function[core::ops::function::Fn::call::h80ff1f496bb96ef1]@[wasm code]
<?>.wasm-function[std::panicking::rust_panic_with_hook::h70a0e195f4db2a29]@[wasm code]
<?>.wasm-function[std::panicking::begin_panic_handler::{{closure}}::hdcfc819ce836829e]@[wasm code]
<?>.wasm-function[std::sys_common::backtrace::__rust_end_short_backtrace::h53cabafab5b09ada]@[wasm code]
<?>.wasm-function[rust_begin_unwind]@[wasm code]
<?>.wasm-function[core::panicking::panic_fmt::h751be80779d42b53]@[wasm code]
<?>.wasm-function[std::time::Instant::now::h191947beee8509bf]@[wasm code]
<?>.wasm-function[tokio::time::instant::variant::now::h3c864f6578f780bc]@[wasm code]
<?>.wasm-function[tokio::time::instant::Instant::now::haaab15ba5b70db5b]@[wasm code]
<?>.wasm-function[tokio::time::driver::sleep::sleep::ha840de8dc1dc85fb]@[wasm code]
<?>.wasm-function[<backoff::future::TokioSleeper as backoff::future::Sleeper>::sleep::hd6eb274f5257e1c5]@[wasm code]
<?>.wasm-function[<backoff::future::Retry<S,B,N,Fn,Fut> as core::future::future::Future>::poll::h5307a8e7cbba1773]@[wasm code]

When the backoff crate has the wasm-bindgen feature enabled, it would be ideal if it leaned on another form of sleeping, such as using gloo-timer, or if there was a way to choose the time that is used. I note that this crate already uses instant instead of std Instant, so something like this would be aligned with that.

@leighmcculloch
Copy link
Author

leighmcculloch commented Nov 17, 2022

I got backoff working with the following change, and using it in place of the TokioSleeper when using wasm-bindgen.

#[cfg(feature = "gloo-timers")]
#[cfg_attr(docsrs, doc(cfg(feature = "gloo-timers")))]
struct GlooTimersSleeper;

#[cfg(feature = "gloo-timers")]
#[cfg_attr(docsrs, doc(cfg(feature = "gloo-timers")))]
impl Sleeper for GlooTimersSleeper {
    type Sleep = ::gloo_timers::future::TimeoutFuture;
    fn sleep(&self, dur: Duration) -> Self::Sleep {
        ::gloo_timers::future::sleep(dur)
    }
}

@wackazong
Copy link

wackazong commented Jan 24, 2023

I got backoff working with the following change, and using it in place of the TokioSleeper when using wasm-bindgen.

#[cfg(feature = "gloo-timers")]
#[cfg_attr(docsrs, doc(cfg(feature = "gloo-timers")))]
struct GlooTimersSleeper;

#[cfg(feature = "gloo-timers")]
#[cfg_attr(docsrs, doc(cfg(feature = "gloo-timers")))]
impl Sleeper for GlooTimersSleeper {
    type Sleep = ::gloo_timers::future::TimeoutFuture;
    fn sleep(&self, dur: Duration) -> Self::Sleep {
        ::gloo_timers::future::sleep(dur)
    }
}

Does not work for me, I get the following error:

264 |     type Sleep = ::gloo_timers::future::TimeoutFuture;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn FnMut() + 'static)` cannot be sent between threads safely

@leighmcculloch would you be able to share a working example? I am currently stuck here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants