Skip to main content

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}