Skip to main content

qubit_http/sse/
sse_reconnect_options.rs

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