In diesem Leitfaden wird beschrieben, wie Sie die „inkrementelle Synchronisierung“ von Kalenderdaten implementieren. Mit dieser Methode können Sie die Daten für alle Kalendersammlungen synchronisieren und gleichzeitig die Bandbreite sparen.
Inhalt
Übersicht
Die inkrementelle Synchronisierung besteht aus zwei Phasen:
Die anfängliche vollständige Synchronisierung wird nur einmal zu Beginn durchgeführt, um den Status des Clients vollständig mit dem Status des Servers zu synchronisieren. Der Client erhält ein Synchronisierungstoken, das er beibehalten muss.
Die inkrementelle Synchronisierung wird wiederholt durchgeführt und aktualisiert den Client mit allen Änderungen, die seit der letzten Synchronisierung stattgefunden haben. Jedes Mal gibt der Client das vorherige Synchronisierungstoken an, das er vom Server erhalten hat, und speichert das neue Synchronisierungstoken aus der Antwort.
Erste vollständige Synchronisierung
Die anfängliche vollständige Synchronisierung ist die ursprüngliche Anfrage für alle Ressourcen der Sammlung, die Sie synchronisieren möchten. Optional können Sie die Listenanfrage mithilfe von Anfrageparametern einschränken, wenn Sie nur eine bestimmte Teilmenge von Ressourcen synchronisieren möchten.
In der Antwort auf den Listenvorgang finden Sie das Feld nextSyncToken
, das ein Synchronisierungstoken darstellt. Sie müssen den Wert von nextSyncToken
speichern. Wenn die Ergebnismenge zu groß ist und die Antwort in Seiten aufgeteilt wird, ist das Feld nextSyncToken
nur auf der letzten Seite vorhanden.
Inkrementelle Synchronisierung
Bei der inkrementellen Synchronisierung können Sie alle Ressourcen abrufen, die seit der letzten Synchronisierungsanfrage geändert wurden. Dazu müssen Sie eine Listenanfrage mit Ihrem letzten Synchronisierungstoken ausführen, das im Feld syncToken
angegeben ist.
Das Ergebnis enthält immer gelöschte Einträge, damit die Clients die Möglichkeit haben, sie aus dem Speicher zu entfernen.
Wenn sich seit der letzten inkrementellen Synchronisierungsanfrage eine große Anzahl von Ressourcen geändert hat, wird in den Listenergebnissen möglicherweise ein pageToken
anstelle eines syncToken
angezeigt. In diesen Fällen müssen Sie dieselbe Listenabfrage ausführen, die auch für den Abruf der ersten Seite bei der inkrementellen Synchronisierung verwendet wurde (mit genau derselben syncToken
), fügen Sie die pageToken
an und blättern Sie durch alle folgenden Anfragen, bis Sie auf der letzten Seite eine weitere syncToken
finden. Speichern Sie diese syncToken
für die nächste Synchronisierungsanfrage.
Hier sind Beispielabfragen für einen Fall, bei dem eine inkrementelle paginatierte Synchronisierung erforderlich ist:
Ursprüngliche Suchanfrage
GET /calendars/primary/events?maxResults=10&singleEvents=true&syncToken=CPDAlvWDx70CEPDAlvWDx
// Result contains the following
"nextPageToken":"CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA",
Nächste Seite wird abgerufen
GET /calendars/primary/events?maxResults=10&singleEvents=true&syncToken=CPDAlvWDx70CEPDAlvWDx&pageToken=CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA
Vollständige Synchronisierung vom Server erforderlich
Manchmal werden Synchronisierungstokens aus verschiedenen Gründen vom Server ungültig gemacht, z. B. aufgrund von Ablauf des Tokens oder Änderungen an den zugehörigen ACLs.
In solchen Fällen antwortet der Server auf eine inkrementelle Anfrage mit dem Antwortcode 410
. Dadurch sollte der Cache des Clients vollständig gelöscht und eine neue vollständige Synchronisierung ausgelöst werden.
Beispielcode
Im folgenden Codebeispiel wird gezeigt, wie Synchronisierungstokens mit der Java-Clientbibliothek verwendet werden. Bei der ersten Ausführung der Run-Methode wird eine vollständige Synchronisierung durchgeführt und das Synchronisierungstoken gespeichert. Bei jeder weiteren Ausführung wird das gespeicherte Synchronisierungstoken geladen und eine inkrementelle Synchronisierung durchgeführt.
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."); }
Legacy-Synchronisierung
Bei Ereignissammlungen ist es weiterhin möglich, die Synchronisierung auf die bisherige Weise durchzuführen. Dazu wird der Wert des aktualisierten Felds aus einer Ereignislistenanfrage beibehalten und dann mithilfe des Felds modifiedSince
aktualisierte Ereignisse abgerufen.
Dieser Ansatz wird nicht mehr empfohlen, da er anfälliger für verpasste Aktualisierungen ist (z. B. wenn keine Abfrageeinschränkungen erzwungen werden).
Außerdem ist sie nur für Ereignisse verfügbar.