qubit_http/sse/sse_reconnect_options.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! Options and defaults for SSE reconnect with backoff.
10//!
11//! # Author
12//!
13//! Haixing Hu
14
15use std::time::Duration;
16
17use crate::{RetryDelay, RetryJitter, RetryOptions};
18
19/// Default upper bound for SSE reconnect delay backoff.
20pub(crate) const DEFAULT_SSE_MAX_RECONNECT_DELAY: Duration = Duration::from_secs(30);
21
22/// Default exponential backoff multiplier for SSE reconnect delay growth.
23pub(crate) const DEFAULT_SSE_RECONNECT_BACKOFF_MULTIPLIER: f64 = 2.0;
24
25/// Default maximum reconnect attempts after the initial stream open.
26pub(crate) const DEFAULT_SSE_MAX_RECONNECTS: u32 = 3;
27
28/// Builds default retry options for SSE reconnect.
29///
30/// # Returns
31/// Retry options matching SSE reconnect defaults.
32fn default_sse_retry_options() -> RetryOptions {
33 RetryOptions::new(
34 DEFAULT_SSE_MAX_RECONNECTS + 1,
35 None,
36 None,
37 RetryDelay::exponential(
38 Duration::from_secs(1),
39 DEFAULT_SSE_MAX_RECONNECT_DELAY,
40 DEFAULT_SSE_RECONNECT_BACKOFF_MULTIPLIER,
41 ),
42 RetryJitter::None,
43 )
44 .expect("SSE default retry options must be valid")
45}
46
47/// Reconnect behavior options for [`crate::HttpClient::execute_sse_with_reconnect`].
48#[derive(Debug, Clone, PartialEq)]
49pub struct SseReconnectOptions {
50 /// Retry options used by SSE reconnect delay calculation.
51 ///
52 /// `max_attempts` includes the initial stream-open attempt, so if callers
53 /// want at most `N` reconnects they should pass `max_attempts = N + 1`.
54 pub retry: RetryOptions,
55 /// Whether to reconnect when the SSE stream ends without an explicit error.
56 pub reconnect_on_eof: bool,
57 /// Whether to honor SSE `retry:` field as the next reconnect delay.
58 pub honor_server_retry: bool,
59 /// Optional upper bound applied to SSE `retry:` delay values from server
60 /// events.
61 ///
62 /// When `None`, reconnect runner derives a cap from retry delay strategy
63 /// when it has explicit max (`Random` / `Exponential`), otherwise it uses
64 /// internal default bound.
65 pub server_retry_max_delay: Option<Duration>,
66 /// Whether jitter should be applied when the reconnect delay comes from SSE
67 /// `retry:` field.
68 pub apply_jitter_to_server_retry: bool,
69}
70
71impl Default for SseReconnectOptions {
72 /// Builds default SSE reconnect options.
73 ///
74 /// # Returns
75 /// Default reconnect options with bounded reconnect attempts.
76 fn default() -> Self {
77 Self {
78 retry: default_sse_retry_options(),
79 reconnect_on_eof: true,
80 honor_server_retry: true,
81 server_retry_max_delay: None,
82 apply_jitter_to_server_retry: true,
83 }
84 }
85}
86
87impl SseReconnectOptions {
88 /// Creates default SSE reconnect options.
89 ///
90 /// # Returns
91 /// Same as [`SseReconnectOptions::default`].
92 pub fn new() -> Self {
93 Self::default()
94 }
95}