1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//! Back off when Telegram says to (#814).
//!
//! The plan card was writing often enough to trip flood control, and the error
//! was logged and dropped. Nothing recorded that the API had asked for a pause,
//! so the next refresh wrote again immediately and each rejected attempt kept
//! the window alive. Observed as roughly twenty create attempts across forty
//! seconds while the countdown ticked 40s down to 3s without ever elapsing.
//!
//! The card is chrome. Skipping an update is strictly better than being
//! throttled into a loop that also spams duplicates into the chat.
use Duration;
/// Seconds Telegram asked us to wait, from an error string.
///
/// teloxide surfaces flood control as text containing `Retry after N`, so this
/// matches on that rather than a typed variant, which keeps it working across
/// the several error shapes the same condition arrives in.
///
/// Returns `None` for anything else, so ordinary failures (a deleted message,
/// bad markup) are not mistaken for throttling and do not suppress writes.
pub
/// Extra margin added to the window Telegram gives.
///
/// Resuming on the exact second risks landing inside the same window and
/// renewing the penalty, which is the loop this exists to break.
pub const RETRY_MARGIN: Duration = from_secs;
/// Longest 429 wait any send path may sleep inline (#1064).
///
/// Telegram can hand out multi-hour windows (8288s observed on a flooded
/// chat). Sleeping the full window inside the send call parked the whole
/// agent turn for hours: the reply was already computed, the process just
/// sat in `tokio::time::sleep` waiting to deliver it. Typical flood windows
/// (placeholder-edit churn, command bursts) are seconds and stay under the
/// cap, so their behavior is unchanged. Oversized windows are slept up to
/// the cap, the retry fails again, and the existing never-silent error
/// paths (#1019) take over. Every send path shares this policy through
/// [`wait_out`].
pub const MAX_INLINE_RATE_LIMIT_WAIT: Duration = from_secs;
/// The inline wait for a 429: the requested window, clamped to
/// [`MAX_INLINE_RATE_LIMIT_WAIT`]. `capped` tells callers whether the log
/// line should say the wait was shortened (forensics: a capped wait means
/// the chat was flood-banned, not merely throttled).
pub
/// Clamp the requested 429 window and sleep it, logging one standardized
/// line (#1085 P1b R1 — this warn+sleep block was copy-pasted at four send
/// sites with drifting wording). `what` names the send ("HTML send",
/// "edit", ...); `extra` carries per-site context such as an attempt
/// counter or message id into the line. The capped branch's wording is
/// forensic, do not soften it: a window over the cap means the chat is
/// flood-banned, not merely throttled (#1064).
pub async