先定義同步語意,再選擇分頁方式
分頁不只是把 page 參數加一。工程團隊首先要確認來源 API 在同步期間如何看待資料變動。若採用 offset 分頁,而來源同時新增或刪除資料,後續頁面的位移可能改變,造成重複或遺漏。資料量小、排序穩定且允許重新掃描時,offset 簡單易懂;持續變動的交易、工單或客戶資料,通常更適合 cursor 分頁或以遞增欄位進行 keyset pagination。
游標也不能被當成永久有效的進度。供應方可能讓游標過期、限制其使用時間,或在版本更新後改變格式。同步程序應保存最後成功提交的業務水位,例如 updated_at 加上唯一 ID,而不是只保存不透明的 next_cursor。當時間戳精度不足或多筆資料可能同時更新時,必須使用複合排序鍵,例如先按 updated_at、再按 id 排序,並以相同條件查詢下一批。
開始實作前,應把下列問題寫進整合契約:
- 排序是否穩定:每一頁是否使用明確且唯一的排序條件,資料更新會不會改變所在頁面。
- 快照是否一致:整次掃描看到的是固定快照,還是每次請求都讀取當下狀態。
- 游標生命週期:游標是否會過期、能否重複使用,以及失效後應從哪個水位恢復。
- 刪除如何表達:來源是否提供 tombstone、刪除事件或完整比對機制。
- 完成如何判定:以空頁、缺少 next cursor,還是明確的 has_more 欄位為準。
把限流視為排程訊號,而不是例外
收到 HTTP 429 時,立即重送通常只會延長壅塞。客戶端應優先遵守 Retry-After 或供應方提供的重設時間;若沒有明確提示,再使用指數退避並加入隨機抖動,避免多個 worker 同時醒來形成尖峰。重試次數、單次延遲與整體截止時間要分開設定,否則一個批次可能在背景無限等待,表面上仍顯示執行中。
可靠的吞吐量控制不應只靠遇到 429 後降速。可在客戶端使用 token bucket 或固定併發上限,並依 API 路由、租戶或憑證分開管理配額。查詢端點與寫入端點可能使用不同限制,不能共用一個粗略計數器。若回應包含剩餘配額與重設時間,可以逐步調整並行度;若沒有,應從保守值開始,根據延遲、錯誤與待處理佇列觀察調整。
並非所有失敗都適合重試。逾時、連線中斷、429 與部分 5xx 通常可重試,但要受截止時間約束;驗證錯誤、權限不足與格式錯誤需要停止或隔離。對寫入請求而言,逾時不代表伺服器沒有完成操作,因此必須搭配冪等鍵、來源唯一鍵或查詢確認機制,避免重試建立重複資料。
大量同步要能分段提交、重跑與對帳
把數十萬筆資料視為一個交易,通常會讓恢復成本過高。更實際的方式是將工作拆成有明確邊界的批次:讀取一頁、驗證與轉換、寫入目的端、確認提交,再更新 checkpoint。checkpoint 必須在目的端成功提交後才前進;若先記錄進度再寫入,程序中斷時就可能永久跳過資料。
目的端應採用依業務鍵 upsert,並保存來源版本、更新時間或雜湊,讓相同批次重跑時得到相同結果。若來源事件可能亂序,僅比較接收時間並不安全;應使用來源版本或可比較的業務時間判斷是否覆寫。無法處理的個別資料可送入隔離佇列,記錄原始輸入、錯誤類型與重試狀態,避免一筆壞資料阻塞整個同步,同時也不能悄悄略過。
- 首次全量:以固定切點建立基準資料,並記住掃描開始時的增量水位。
- 追補增量:全量完成後,從先前水位重播變更,填補掃描期間產生的更新。
- 定期對帳:比較筆數、主鍵集合、更新範圍或分桶雜湊,找出靜默遺漏。
- 刪除同步:優先使用刪除事件;若來源不提供,安排週期性完整比對並審慎執行刪除。
用可觀測性證明同步正確,而不只是完成
一個 job 顯示成功,只代表程式走到結尾,不代表資料完整。至少要觀察每批讀取、寫入、略過、重試、失敗與隔離的筆數,以及目前 checkpoint、來源延遲和最舊未處理資料的時間。日誌應帶有同步工作 ID、租戶、端點、頁面或游標摘要與批次 ID,但不應記錄存取權杖或完整敏感資料。
告警條件也要反映業務風險。除了連續失敗,還要偵測同步長時間沒有前進、某頁反覆重跑、來源有新資料但寫入量為零,以及隔離佇列持續累積。重啟程序應能讀取 checkpoint,自動恢復,而不是要求工程師手動猜測從哪一頁開始;人工介入則應提供重放單一批次、跳過已確認壞資料及重新對帳的操作方式。
最後,應用故障注入驗證設計:在讀取後中斷、在寫入逾時、讓游標失效、模擬 429,並讓同一批次執行兩次。若系統能在這些情境下恢復、維持冪等,且對帳結果一致,才算具備可上線的大量同步能力。跨 LINE、ERP、CRM、雲端與 IoT 平台的整合尤其需要這種紀律;必要時,可由熟悉兩端資料語意的整合團隊共同定義契約與恢復流程。