pub struct PushHealth { /* private fields */ }Expand description
v1.4.83 §9 F2-F6 推送通道健康追踪。
所有字段 atomic 无锁,安全跨 sync push callback / async dispatcher / async orphan scan task / REST handler 多个执行上下文。
关键约束:
last_push_received_at_ms:自 daemon 启动后任意 push 收到就更新; 用作 staleness watermark(/api/push-subscriber-infoF5 暴露)consecutive_parse_errors:成功 push 清零;失败 += 1;触发 F3/F4total_parse_errors:monotonic,用于 metrics rate 计算circuit_breaker_tripped_ms:F4 tripped 时写入 Unix ms;dispatcher 在now - tripped_ms < 30_000时跳过 dispatch(30s cooldown)
Implementations§
Source§impl PushHealth
impl PushHealth
Sourcepub fn record_f2_exhausted(&self, acc_id: u32) -> bool
pub fn record_f2_exhausted(&self, acc_id: u32) -> bool
v1.4.90 P2-B: 调用时机 = F2 retry 4 次全失败 (retry_with_exp_backoff
返 Err). 记录该 acc_id 的 exhausted 事件; 若 30 min 窗口内 >= 3 次 →
trip circuit + return true (caller log warn 一次 + ++counter).
返 false = 未 trip (caller 只 log debug); 返 true = 刚 trip (caller log
warn + ++ f2_circuit_tripped_total).
Sourcepub fn is_f2_circuit_tripped(&self, acc_id: u32) -> bool
pub fn is_f2_circuit_tripped(&self, acc_id: u32) -> bool
v1.4.90 P2-B: 调用时机 = dispatcher 准备给 acc_id 起 F2 retry 之前. 返 true → caller 应 skip 本次 retry (账户在 cooldown 内); 返 false → 正常 retry.
1h cooldown 过则自动 reset (清 tripped_at_ms + 清 exhaust window).
Source§impl PushHealth
impl PushHealth
pub fn new() -> Self
Sourcepub fn record_push_success(&self)
pub fn record_push_success(&self)
调用时机:每次 push callback 成功 parse/dispatch。
更新 last_push_received_at_ms + clear consecutive_parse_errors
- increment
total_pushes_received.
若之前 circuit tripped 且 cooldown 过了 → auto-reset(F4 自动恢复路径)。
Sourcepub fn record_qot_push_sub_type(&self, sub_type: i32)
pub fn record_qot_push_sub_type(&self, sub_type: i32)
Record a regular QOT push dispatch watermark by FTAPI SubType.
This intentionally lives beside, not inside, record_push_success():
the backend callback only knows CMD6212, while the dispatcher knows the
decoded FTAPI sub_type. Direct first-push cache replays do not call
this method because they are synthetic cache events, not backend stream
freshness evidence.
Sourcepub fn record_parse_error(&self) -> u32
pub fn record_parse_error(&self) -> u32
调用时机:push parse 失败(proto decode / 字段缺 / 非法值)。 返回当前 consecutive_errors 值(caller 据此决定是否触发 F3/F4)。
Sourcepub fn record_resubscribe(&self)
pub fn record_resubscribe(&self)
F3 re-subscribe 触发时调用,更新 counter + 时间戳 + clear 计数.
Sourcepub fn record_resubscribe_partial(&self, missed_keys: u32)
pub fn record_resubscribe_partial(&self, missed_keys: u32)
v1.4.106 codex 0631 F4 [P2]: resubscribe 部分失败触发时调用.
missed_keys = cache miss / unresolved sec_keys 数 (0 = 全部 resolve OK).
dispatcher / health 检查器 据本字段判 push stream degraded.
Sourcepub fn trip_circuit(&self)
pub fn trip_circuit(&self)
F4 circuit breaker trip 触发时调用.
Sourcepub fn is_circuit_tripped_now(&self) -> bool
pub fn is_circuit_tripped_now(&self) -> bool
F4 lightweight state read for threshold checks that must not trigger the
cooldown auto-reset side effect in should_skip_dispatch().
Sourcepub fn should_skip_dispatch(&self) -> bool
pub fn should_skip_dispatch(&self) -> bool
F4 check: dispatcher 每个 event 开头调,tripped 且 cooldown 内 → skip dispatch return true (跳过); tripped 但 cooldown 过 → auto-reset return false; 未 tripped → return false.
Sourcepub fn record_orphan_scan(&self, orphan_count: u64)
pub fn record_orphan_scan(&self, orphan_count: u64)
F6 orphan scan 发现 N 个卡住订单时调(N > 0 才调).
Sourcepub fn record_trade_requery_dropped(
&self,
reason: &'static str,
notice_type: u32,
) -> u64
pub fn record_trade_requery_dropped( &self, reason: &'static str, notice_type: u32, ) -> u64
v1.4.106 codex 0932 F1: 调用时机 = push_tx.try_send(TradeReQuery { .. })
返 Err(TrySendError::Full | Closed). 全部 silent drop 路径都改为
调用本方法 + bump counter + log warn 1 次.
reason = “queue_full” / “queue_closed”;
notice_type = backend NotifyMsg.notice_type (4 / 6 / 100 / 101 / etc.)
返新的 dropped_total 值 — caller 可据此判定 “首次 drop 触发 warn” 但本实装由 caller 简单 log_warn (caller 已有 acc_id / order_ids context).
Sourcepub fn is_healthy(&self) -> bool
pub fn is_healthy(&self) -> bool
F5 暴露给 /api/push-subscriber-info: 是否 push stream 健康.
规则:同时满足才判 healthy:
- circuit 未 tripped
consecutive_parse_errors < 5last_push_received_at_ms!= 0 且now - last < 60_000(60s 内有 push) OR daemon 刚启动 < 60s(没 push 不等于不健康,可能还没订阅)- v1.4.106 codex 0932 F1: 60s 内 没 发生 TradeReQuery 队列丢弃 (队列满 = backpressure, 短期内 dispatcher 无法消费完, 上层应感知)
Sourcepub fn compute_degraded_reason(&self) -> Option<String>
pub fn compute_degraded_reason(&self) -> Option<String>
v1.4.106 codex 0631 F4 [P2]: 计算 degraded reason — 与 is_healthy()
同源逻辑, 但返人类可读字符串 (供 REST /api/push-subscriber-info
用户排查 / Prometheus alert label).
优先级 (与 is_healthy() 一致):
- circuit_breaker tripped
- consecutive parse errors >= 5
- trade requery queue dropped < 60s
- resubscribe partial failure < 60s
- no push received >= 60s
Sourcepub fn snapshot(&self) -> PushHealthSnapshot
pub fn snapshot(&self) -> PushHealthSnapshot
F5 snapshot: REST / 诊断层批量读取用.
Sourcepub fn render_prometheus(&self) -> String
pub fn render_prometheus(&self) -> String
Render push-health state as Prometheus text exposition.
This mirrors the existing /api/push-subscriber-info snapshot instead
of introducing another metrics state source.