12 个版本 (5 个破坏性更新)
0.6.0 | 2021 年 12 月 2 日 |
---|---|
0.5.0 | 2021 年 10 月 26 日 |
0.4.3 | 2021 年 10 月 12 日 |
0.4.0 | 2021 年 9 月 26 日 |
0.1.1 | 2021 年 9 月 26 日 |
#1222 在 异步
153 每月下载量
在 2 crates 中使用
47KB
892 行
fure
一个用于重试 futures 的 crate。
Policy
trait 将帮助您定义不同的重试策略。
一些内置策略可以在 policies
模块中找到。
默认情况下,此 crate 使用 tokio
定时器来实现 crate::policies::interval
和 crate::policies::backoff
策略,但也可以作为功能 async-std
使用。
示例。
间隔重试。
开始发送请求,设置 1 秒定时器,并等待其中之一。
如果定时器先完成(这意味着请求在 1 秒内没有完成),则再发送一个请求。
如果请求先完成并且它有一个 [Ok
] 响应,则返回该响应;如果请求有一个 [Err
] 响应,则定时器重置,并再次发送新的请求。
最多发送 4 个请求。
use fure::policies::{interval, attempts};
use std::time::Duration;
let get_body = || async {
reqwest::get("https://www.rust-lang.net.cn")
.await?
.text()
.await
};
let policy = attempts(interval(Duration::from_secs(1)), 3);
let body = fure::retry(get_body, policy).await?;
println!("body = {}", body);
带有退避的顺序重试。
使用指数退避和抖动重试失败的请求。
use fure::{policies::{backoff, cond}, backoff::{exponential, jitter}};
use std::time::Duration;
let get_body = || async {
reqwest::get("https://www.rust-lang.net.cn")
.await?
.text()
.await
};
let exp_backoff = exponential(Duration::from_secs(1), 2, Some(Duration::from_secs(10)))
.map(jitter);
let policy = cond(backoff(exp_backoff), |result| !matches!(result, Some(Ok(_))));
let body = fure::retry(get_body, policy).await?;
println!("body = {}", body);
实现您自己的策略。
它的行为类似于上面的间隔策略,但如果它达到 TOO_MANY_REQUESTS
,则会在发送下一个请求之前等待几秒钟。
use std::{future::{Future, ready}, pin::Pin, time::Duration};
use fure::Policy;
use reqwest::{Error, Response, StatusCode};
struct RetryPolicy;
impl Policy<Response, Error> for RetryPolicy {
type ForceRetryFuture = tokio::time::Sleep;
type RetryFuture = Pin<Box<dyn Future<Output = Self>>>;
fn force_retry_after(&self) -> Self::ForceRetryFuture {
tokio::time::sleep(Duration::from_millis(100))
}
fn retry(
self,
result: Option<Result<&Response, &Error>>,
) -> Option<Self::RetryFuture> {
match result {
Some(Ok(response)) => match response.status() {
StatusCode::OK => None,
StatusCode::TOO_MANY_REQUESTS => {
let retry_after_secs: u64 = response
.headers()
.get("Retry-After")
.and_then(|x| x.to_str().ok()?.parse().ok())
.unwrap_or(1);
Some(Box::pin(async move {
tokio::time::sleep(Duration::from_secs(retry_after_secs)).await;
self
}))
}
_ => Some(Box::pin(ready(self))),
},
_ => Some(Box::pin(ready(self))),
}
}
}
let get_response = || reqwest::get("https://www.rust-lang.net.cn");
let response = fure::retry(get_response, RetryPolicy).await?;
println!("body = {}", response.text().await?);
许可:MIT
依赖项
~2–12MB
~138K SLoC