Skip to content

fix(eew): detect and recover from silently dropped live feeds - #614

Merged
whes1015 merged 4 commits into
mainfrom
fix/realtime-feed-liveness
Oct 16, 2026
Merged

whes1015 merged 4 commits into
mainfrom
fix/realtime-feed-liveness

Conversation

@whes1015

@whes1015 whes1015 commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Stack 第 1/7 層:#614 → #616 → #615 → #618 → #619 → #620 → #621,請由下往上合併。這是最底層,base 是 main。

這個 PR 做了什麼

地震速報(EEW)和即時測站(RTS)的 SSE 連線,在網路切換或 NAT 逾時後可能變成「半斷」:socket 沒有關閉、沒有錯誤,只是再也收不到資料。原本的設計把「連線開著」當作存活,所以這時畫面會一直顯示「已連線、無警報」,下一則速報卻永遠送不進來。這個 PR 讓 app 能發現這種狀況並重新連線;連線中斷期間,改用 API 輪詢補上速報。

改動內容

正式程式碼

  • 823c7855 偵測半斷連線
    • sse_client.dart:伺服器每 60 秒送的 : ping 原本被直接丟掉,現在改成交給上層,當作「連線還活著」的證據,但不會被當成資料解析。
    • sse_realtime_source.dart:記錄最後一次收到任何位元組的時間。超過 sseSilenceLimit(132 秒 = 2.2 × 60 秒 ping)沒收到東西,就回報錯誤並重連。為什麼是 2.2 倍:LB hub 只在等待結束時檢查要不要送 ping,健康但安靜的連線兩個位元組之間最長可能接近兩個間隔。
    • api_client.dart:SSE 請求原本把 receiveTimeout 設為 0(關閉),改成同一個上限。這樣 app 在 inactive(例如拉下通知欄)時,半斷的連線也會被換掉。
    • rts_realtime_source.dart:RTS 睡眠模式下原本「沒資料就是平靜」,現在超過上限的沉默不再當作平靜。
  • 0cb0fc2e 重連加入 ±50% 隨機抖動:原本固定 1/2/3 秒。伺服器重啟時,所有裝置不會在同一瞬間湧入。
  • dca90459 網路一變就重連
    • 新增 NetworkChannel.kt(Android)和 NetworkPlugin.swift(iOS)兩個原生 channel,回報網路變化。沒有加 connectivity_plus,照 repo 偏好原生實作的原則。Android 新增 ACCESS_NETWORK_STATE 權限。
    • 透過 RealtimeService 分送給各個 source:網路真的換了(Wi-Fi ↔ 行動網路、離線 → 上線)就丟掉舊 socket、重設退避,隨機等 1–2 秒後重連。
    • inactive 時保留 socket 的既有行為不變。
  • b084e0d2 連線中斷時輪詢速報
    • EEW 串流斷線超過 3 秒後,每 10 秒呼叫一次既有的 getEewRealtime,走同一套解碼和 JMA/只看 CWA 的過濾。
    • 輪詢來的結果狀態最多是 stale,不會是 live:10 秒一次的快照做不到 live 承諾的即時,所以速報會顯示在地震速報頁,並帶「資料可能已過期」的提示。
    • 串流一恢復就停止輪詢,還在途中的那次結果直接丟棄。
  • ARCHITECTURE.md § Realtime feeds 跟著每個 commit 更新,因為那份文件就是這些行為的契約。

測試

  • parser 處理 ping、idle timeout、沉默上限、抖動、網路變化與過濾、RealtimeService 分送、輪詢回退,以及 staleness 分類在回退資料下的行為。
  • 原本鎖死「連線開著但沉默就一直算正常」的測試,改成有上限的版本。

相關 issue

沒有對應的 issue,是比對各端連線處理時發現的。

怎麼驗

  • tool/commit.sh --push 通過:analyze、codegen、全部 Dart 測試。
  • Android debug APK 和 iOS 模擬器 app 都建置成功,tool/dev/test_ios.sh 通過。
  • 還沒在實機上測,合併前建議做:
    • 開著地震速報頁,Wi-Fi ↔ 行動網路來回切換,確認幾秒內重新連上。
    • 開關飛航模式一次。
    • 半斷連線(例如讓路由器的 NAT 表過期),確認約 132 秒內發現並重連。
  • 已知限制: iOS 在兩個 Wi-Fi 之間切換時介面名稱不變(都是 wifi:en0),這種情況仍要等沉默上限才會發現。

伺服器心跳維持 60 秒,不調整。 一般 TCP 斷線會直接觸發錯誤並重連,這個 132 秒的上限只是給「沒有 FIN、沒有 RST」那種半斷連線的保底,不需要更短的心跳。

檢查清單

  • tool/check/commits.sh origin/main..HEAD 通過
  • 一個 commit 一件事
  • analyze 與測試通過(tool/commit.sh --push)
  • 新的使用者可見字串都走 AppLocalizations(沒有新增字串,沿用既有的過期提示)
  • 沒有新的 UI 元件

@codecov

codecov Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.45223% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.43%. Comparing base (807f5d9) to head (b084e0d).

Files with missing lines Patch % Lines
lib/bootstrap.dart 0.00% 2 Missing ⚠️
lib/core/realtime/realtime_source.dart 50.00% 1 Missing ⚠️
lib/features/earthquake/earthquake_providers.dart 75.00% 1 Missing ⚠️

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

lowrt
lowrt previously approved these changes Oct 16, 2026

@lowrt lowrt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已測
開著地震速報頁,Wi-Fi ↔ 行動網路來回切換,確認幾秒內重新連上。
開關飛航模式一次。

約2.5~5秒重新連上

Platform: all

Fix(zh-Hant): 修正網路切換後地震速報連線已中斷卻仍顯示連線正常,現在會自動發現並重新連線
Fix(en-US): the earthquake alert feed no longer shows as connected after a network switch silently cut it off; it now notices and reconnects
Platform: all

Optimization(zh-Hant): 伺服器中斷後各裝置錯開時間重新連線,恢復時不再一起湧入,速報連線更快恢復
Optimization(en-US): devices now reconnect at staggered times after a server outage instead of all at once, so the alert feed recovers faster
Platform: all

Fix(zh-Hant): 切換 Wi-Fi 與行動網路或重新連上網路後,地震速報與即時測站連線會立即重新建立,不必等到逾時
Fix(en-US): switching between Wi-Fi and mobile data, or coming back online, now reconnects the earthquake alert and station feeds at once instead of waiting for a timeout
Platform: all

Fix(zh-Hant): 速報即時連線中斷時改為每 10 秒查詢一次,期間發布的速報仍會出現在地震速報頁,並標示資料可能已過期
Fix(en-US): while the live alert connection is down, the app checks for alerts every 10 seconds, so one issued meanwhile still appears on the early warning page, marked as possibly out of date
@whes1015

Copy link
Copy Markdown
Member Author

Force-push:rebase 到目前的 main(807f5d9d),並把開著的 PR 排成 stack:#614 → #616 → #615 → #618 → #619 → #620 → #621,base 改成下面那一層的分支。

和 main 及其他 PR 的衝突都是兩邊各自新增的內容,雙方都保留;ARB 在檔尾補逗號後重新產生 l10n。每一層都單獨跑過 analyze 和完整測試,頂端跑過 tool/commit.sh --push。

這一層的 commit 內容沒有變,只有上下文不同。

@whes1015
whes1015 added this pull request to stack #626 October 16, 2026 19:21
@whes1015
whes1015 merged commit 238297e into main Oct 16, 2026
8 checks passed
@whes1015
whes1015 deleted the fix/realtime-feed-liveness branch October 16, 2026 19:21
@lowrt lowrt added this to the v26.4 milestone Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants