opensession_api_client/
retry.rs1use std::time::Duration;
2
3use anyhow::{Context, Result};
4use tracing::warn;
5
6pub struct RetryConfig {
8 pub max_retries: usize,
9 pub delays: Vec<u64>,
10}
11
12impl Default for RetryConfig {
13 fn default() -> Self {
14 Self {
15 max_retries: 3,
16 delays: vec![1, 2, 4],
17 }
18 }
19}
20
21pub async fn retry_post(
26 client: &reqwest::Client,
27 url: &str,
28 auth_token: Option<&str>,
29 body: &serde_json::Value,
30 config: &RetryConfig,
31) -> Result<reqwest::Response> {
32 let max_attempts = config.max_retries + 1;
33
34 for attempt in 0..max_attempts {
35 let mut req = client.post(url).header("Content-Type", "application/json");
36 if let Some(token) = auth_token {
37 req = req.bearer_auth(token);
38 }
39
40 match req.json(body).send().await {
41 Ok(resp) if resp.status().is_server_error() => {
42 if attempt < config.delays.len() {
43 let status = resp.status();
44 warn!(
45 "POST attempt {}/{} failed (HTTP {}), retrying in {}s…",
46 attempt + 1,
47 max_attempts,
48 status,
49 config.delays[attempt],
50 );
51 tokio::time::sleep(Duration::from_secs(config.delays[attempt])).await;
52 } else {
53 return Ok(resp);
54 }
55 }
56 Ok(resp) => return Ok(resp),
57 Err(e) => {
58 if attempt < config.delays.len() {
59 warn!(
60 "POST attempt {}/{} failed ({}), retrying in {}s…",
61 attempt + 1,
62 max_attempts,
63 e,
64 config.delays[attempt],
65 );
66 tokio::time::sleep(Duration::from_secs(config.delays[attempt])).await;
67 } else {
68 return Err(e).context("Failed to connect after retries");
69 }
70 }
71 }
72 }
73
74 unreachable!()
75}