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

Unable to get Retry to work #50

Closed
pms1969 opened this issue Mar 2, 2023 · 7 comments
Closed

Unable to get Retry to work #50

pms1969 opened this issue Mar 2, 2023 · 7 comments

Comments

@pms1969
Copy link

pms1969 commented Mar 2, 2023

I'm sure I'm doing something completely stupid, but just can't work it out. In my reproduction of what I'm experiencing in my real project, I just can't get backon working with my future.

use backon::ConstantBackoff;
use backon::Retryable;
use std::error::Error;
use std::thread;
use std::time::Duration;

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn Error>> {
    let _ = foo().retry(&ConstantBackoff::default()).await?;
    Ok(())
}

async fn foo() -> Result<(), Box<dyn Error + Send + Sync>> {
    async { thread::sleep(Duration::from_secs(1)) }.await;
    Ok(())
}

results in the following error

error[E0599]: the method `retry` exists for opaque type `impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>`, but its trait bounds were not satisfied
 --> src/main.rs:9:19
  |
9 |     let _ = foo().retry(&ConstantBackoff::default()).await?;
  |                   ^^^^^ method cannot be called on `impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>` due to unsatisfied trait bounds
  |
  = note: the following trait bounds were not satisfied:
          `<impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>> as FnOnce<()>>::Output = _`
          which is required by `impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>: Retryable<_, _, _, _, impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>>`
          `impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>: FnMut<()>`
          which is required by `impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>: Retryable<_, _, _, _, impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>>`
          `<&impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>> as FnOnce<()>>::Output = _`
          which is required by `&impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>: Retryable<_, _, _, _, &impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>>`
          `&impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>: FnMut<()>`
          which is required by `&impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>: Retryable<_, _, _, _, &impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>>`
          `<&mut impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>> as FnOnce<()>>::Output = _`
          which is required by `&mut impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>: Retryable<_, _, _, _, &mut impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>>`
          `&mut impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>: FnMut<()>`
          which is required by `&mut impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>: Retryable<_, _, _, _, &mut impl Future<Output = Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>>>`

warning: unused import: `backon::Retryable`
 --> src/main.rs:2:5
  |
2 | use backon::Retryable;
  |     ^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

For more information about this error, try `rustc --explain E0599`.
warning: `mvr` (bin "mvr") generated 1 warning
error: could not compile `mvr` due to previous error; 1 warning emitted

I'm completely baffled. I've tried adding in anyhow, thinking it may be doing some magic, but get the same error. What am I doing wrong?

@Xuanwo
Copy link
Owner

Xuanwo commented Mar 2, 2023

Thanks for reaching out!

Here are some problems here:

  • retry is implement on a future generator instead future it self (becuase we need to build the new future every time we need to retry it)
  • The returning error's type is not match.

I have tested the following code locally, may worth a look:

use backon::ConstantBuilder;
use backon::Retryable;
use std::error::Error;
use std::thread;
use std::time::Duration;

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
    // Note here, use `foo` instead of `foo()`
    let _ = foo.retry(&ConstantBuilder::default()).await?;
    Ok(())
}

async fn foo() -> Result<(), Box<dyn Error + Send + Sync>> {
    async { thread::sleep(Duration::from_secs(1)) }.await;
    Ok(())
}

@pms1969
Copy link
Author

pms1969 commented Mar 2, 2023

Ah, Ok. thanks. And what if foo had arguments? like async foo(some_var: &str) -> Result<(), Box<dyn Error + Send + Sync>>

@Xuanwo
Copy link
Owner

Xuanwo commented Mar 2, 2023

like async foo(some_var: &str) -> Result<(), Box<dyn Error + Send + Sync>>

We need to capture it in an async closure, something like:

let f = || async { foo(xxx).await }
f.retry().await

@pms1969
Copy link
Author

pms1969 commented Mar 2, 2023

Magnificent. You're a star 🌟 I had tried some of that; missed out the await inside the closure. Couldn't see the woods for the trees.

Thank you again.

@pms1969 pms1969 closed this as completed Mar 2, 2023
@esemeniuc
Copy link

esemeniuc commented Jul 27, 2023

Thanks for posting this, I have to use it like this

let upsert_res = (|| async {
    current_epoch_store
        .clone()
        .upsert_current_epoch(epoch_info.epoch)
        .await
})
.retry(&ConstantBuilder::default())
.await;

@qrilka
Copy link

qrilka commented Jan 23, 2024

@Xuanwo maybe this recipe could be added to the rustdocs? I also was confused by a similar compiler error .

@Xuanwo
Copy link
Owner

Xuanwo commented Jan 23, 2024

@Xuanwo maybe this recipe could be added to the rustdocs? I also was confused by a similar compiler error .

Makes sense, let me add them.

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

4 participants