Google Calendar APIの差分同期で410 fullSyncRequiredが返ったら、同じsyncTokenを再送し続けず、同期用のローカル状態を全件同期から作り直します。ただし「全件同期し直す」は、Google Calendar上の予定を削除する指示ではありません。アプリ独自のメモや未送信編集まで同じ削除対象にしないよう、保存データの責任範囲を先に分けます。
この記事はCalendar APIのevents.listを使う同期連携の設計・復旧手順です。以下の保存表と世代切替は架空の実装例であり、Googleが提供する一括復旧機能ではありません。実カレンダーの読取・変更・削除、同期プログラムの実行は行っていません。
目次
410のreasonと同期対象を確認する
HTTP 410という数字だけで全復旧を始めず、失敗したAPIとエラーのreasonを確認します。差分同期のsyncToken無効化なのか、別の操作のエラーなのかを分けます。Calendarの同期tokenはaccess tokenやrefresh tokenとは別の位置情報です。
表は横にスクロールできます
| 記録項目 | 確認すること | 混同しない対象 |
|---|---|---|
| 失敗APIとreason | events.listのfullSyncRequiredか | 別の410・認証エラー |
| 接続アカウントとcalendar | どの同期状態を作り直すか | 全利用者の同期 |
| 保存syncToken | 最後に処理確定した位置 | OAuth refresh token |
| query条件 | 初回と差分の対象範囲 | 別の期間・別calendar |
Googleの同期ガイド(新しいタブで開く)は、期限切れや関連ACLの変更などでsyncTokenが無効になり、差分要求へ410を返す場合があると説明しています。410だけで「何日経過したから」と特定の失効期間を断定せず、接続変更や同期中断の記録も確認します。
clientの複製と独自情報を分離する
公式サンプルは、無効tokenを捨て、client側のevent storeを消去してfull syncする流れです。ここでいうstoreを、Google側の予定やアプリの全データと読み替えないでください。自分の実装で何が同期複製に当たるかを定義してから再構築します。
表は横にスクロールできます
| 保存データの架空例 | 責任範囲 | full sync時の扱い |
|---|---|---|
| Calendarから取得した予定の複製 | 同期対象のローカルreplica | 対象calendar・世代を再構築 |
| アプリ内の担当者メモ | アプリ独自の業務情報 | 無条件に消さず分離保全 |
| 未送信の編集・作成要求 | outbound queue | 再送前に重複・競合を確認 |
| Google側の予定 | 取得元のresource | client再構築のために削除しない |
独自メモをevent IDに結び付けているなら、複製の入れ替えが参照を壊さないかを確認します。未送信編集がある場合、取得した現在状態で上書きしてよいとは限りません。双方向同期の競合解決は別に設計し、本稿の読取側復旧だけで解決したと扱いません。
再構築中を空の正常データとして公開しない
一例として、新しい同期世代を作り、ページ取得と保存がすべて成功した時点で有効世代を切り替える方法があります。これはアプリ側の実装選択です。旧世代の表示を許容するか、同期中と表示して操作を制限するかは、業務上許される鮮度や情報管理の方針から決めます。
古いtokenのエラーを空の成功応答に置き換えると、「予定が0件になった」と判断して独自データを消したり、下流へ誤った削除を送ったりする恐れがあります。同期失敗、正常な0件、再構築中を別の状態にします。ACL変更が関係する可能性もあるため、古い複製を誰に見せ続けてよいかも確認します。
表は横にスクロールできます
| 状態 | UIや下流へ渡す意味 | tokenの扱い |
|---|---|---|
| incremental失敗 | 同期失敗・要再構築 | 無効tokenを再利用しない |
| full sync途中 | 未確定の取得結果 | 完了位置として確定しない |
| 全ページ保存成功 | 新しい同期状態を確定可能 | 最終ページのnextSyncTokenを保存 |
| 保存処理が途中失敗 | 再構築未完了 | 成功扱いにせず再開方針へ |
queryとページングを一つの同期単位にする
初回同期で対象範囲を決め、以後はCalendar APIが許すquery条件の組合せを守ります。syncTokenと併用できないパラメータがあるため、期間を適当に変えながら古いtokenを使い回しません。条件を変える場合は、同期範囲の変更として別の基準点を作る必要があるか確認します。
公式資料では、結果が複数ページならnextSyncTokenは最終ページにあります。nextPageTokenは続きのページを取得するための値で、次回の差分同期位置の代用にはしません。差分同期のページングでも、元と同じsyncToken・queryにpageTokenを加え、最後まで処理します。
- 対象アカウント・calendar・query条件を固定してfull syncを開始する。
- nextPageTokenがある間、続きのページを取得して同期複製へ反映する。
- 全ページの保存結果を確認し、最後に得たnextSyncTokenと同期世代を確定する。
- 新しいtokenで次の差分同期を確認し、削除項目を含む更新の扱いを点検する。
この順序の「反映」と「token確定」をどこまで一つのトランザクションにできるかは、利用DBによります。同時確定できない場合は、同じページを再処理しても壊れない保存と、失敗位置の記録が必要です。全ページを取得しただけでDB保存まで完了したとみなさないようにします。
復旧後は予定件数だけで照合しない
件数が同じでも、削除済み予定の残存や更新内容の取りこぼしはあり得ます。対象calendar、同期範囲、最終成功時刻、代表的な更新・削除の反映、独自情報と未送信queueの保持を確認します。実環境での試験は許可された検証用カレンダーと架空予定を使い、無関係な実予定を削除する試験にしません。
復旧完了とは、エラーを隠して処理を続けたことではなく、対象範囲の複製と新しい同期位置が対応し、次の差分処理へ安全に戻れたことです。ログには同期実行ID、対象の内部識別子、ページ処理結果、世代切替結果を残し、予定本文や参加者情報を必要以上に記録しません。
