本指南說明如何實作日曆資料的「漸進式同步處理」。有了這個方法,就可以同步處理所有日曆集合的資料,同時節省頻寬。
目錄
總覽
漸進式同步處理作業包含兩個階段:
為了將用戶端狀態與伺服器狀態完整同步,初始完整同步處理會在一開始執行一次。用戶端會取得需要保存的同步權杖。
漸進式同步處理會重複執行,並將自上次同步處理後發生的所有變更更新至用戶端。每次用戶端都會提供從伺服器取得的前一個同步憑證,並儲存來自回應的新同步憑證。
初始完整同步
初始完整同步處理是針對您要同步處理的集合所有資源的原始要求。如果您只想同步處理特定資源子集,可以選擇使用要求參數限制清單要求。
在清單作業的回應中,您會看到名為 nextSyncToken
的欄位,代表同步處理權杖。您需要儲存 nextSyncToken
的值。如果結果集過大,且回應內容分頁,則 nextSyncToken
欄位只會顯示在最後一個頁面。
漸進式同步
漸進式同步可讓您擷取自上次同步要求以來已修改的所有資源。為此,您需要使用 syncToken
欄位中指定的最新同步憑證執行清單要求。請記住,結果一律會包含已刪除的項目,因此用戶端有機會從儲存空間中移除項目。
如果自上次漸進式同步要求後有大量資源有所變更,清單結果可能會顯示 pageToken
,而非 syncToken
。在這類情況下,您需要執行與在漸進式同步作業中用來擷取第一個頁面完全相同的清單查詢 (syncToken
完全相同),並附加 pageToken
並對以下所有要求進行分頁查詢,直到在最後一頁找到另一個 syncToken
為止。請務必儲存此 syncToken
,以供日後下次同步處理要求使用。
以下是需要漸進式分頁同步的客服案件範例:
原始查詢
GET /calendars/primary/events?maxResults=10&singleEvents=true&syncToken=CPDAlvWDx70CEPDAlvWDx
// Result contains the following
"nextPageToken":"CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA",
擷取下一頁
GET /calendars/primary/events?maxResults=10&singleEvents=true&syncToken=CPDAlvWDx70CEPDAlvWDx&pageToken=CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA
伺服器需要完整同步處理
有時,伺服器會基於各種原因 (包括權杖過期或在相關 ACL 中的變更) 撤銷同步權杖。在這種情況下,伺服器會以回應代碼 410
回應漸進式要求。這樣應該就會觸發完整的用戶端儲存庫抹除作業,並啟動新的完整同步處理作業。
程式碼範例
下方的程式碼片段示範如何將同步權杖與 Java 用戶端程式庫搭配使用。首次呼叫執行方法時,系統會執行完整同步處理作業並儲存同步權杖。之後每次執行作業時,都會載入已儲存的同步憑證,並執行漸進式同步處理。
private static void run() throws IOException { // Construct the {@link Calendar.Events.List} request, but don't execute it yet. Calendar.Events.List request = client.events().list("primary"); // Load the sync token stored from the last execution, if any. String syncToken = syncSettingsDataStore.get(SYNC_TOKEN_KEY); if (syncToken == null) { System.out.println("Performing full sync."); // Set the filters you want to use during the full sync. Sync tokens aren't compatible with // most filters, but you may want to limit your full sync to only a certain date range. // In this example we are only syncing events up to a year old. Date oneYearAgo = Utils.getRelativeDate(java.util.Calendar.YEAR, -1); request.setTimeMin(new DateTime(oneYearAgo, TimeZone.getTimeZone("UTC"))); } else { System.out.println("Performing incremental sync."); request.setSyncToken(syncToken); } // Retrieve the events, one page at a time. String pageToken = null; Events events = null; do { request.setPageToken(pageToken); try { events = request.execute(); } catch (GoogleJsonResponseException e) { if (e.getStatusCode() == 410) { // A 410 status code, "Gone", indicates that the sync token is invalid. System.out.println("Invalid sync token, clearing event store and re-syncing."); syncSettingsDataStore.delete(SYNC_TOKEN_KEY); eventDataStore.clear(); run(); } else { throw e; } } List<Event> items = events.getItems(); if (items.size() == 0) { System.out.println("No new events to sync."); } else { for (Event event : items) { syncEvent(event); } } pageToken = events.getNextPageToken(); } while (pageToken != null); // Store the sync token from the last request to be used during the next execution. syncSettingsDataStore.set(SYNC_TOKEN_KEY, events.getNextSyncToken()); System.out.println("Sync complete."); }
舊版同步處理
針對事件集合,您還是可以透過舊版方式執行同步處理,方法是保留事件清單要求中的更新後的欄位值,然後使用 modifiedSince
欄位擷取更新後的事件。我們不建議使用這個方法,因為這樣較容易發生更新錯誤 (例如未強制執行查詢限制時),就比較容易出錯。而且僅適用於活動。