Ressourcen effizient synchronisieren

In diesem Leitfaden wird beschrieben, wie Sie die "inkrementelle Synchronisierung" von Kalenderdaten implementieren. Mit dieser Methode können Sie Daten für alle Kalendersammlungen synchron halten und gleichzeitig Bandbreite sparen.

Inhalt

Überblick

Die inkrementelle Synchronisierung besteht aus zwei Phasen:

  1. Die erste vollständige Synchronisierung wird ganz am Anfang durchgeführt, um den Status des Clients vollständig mit dem Status des Servers zu synchronisieren. Der Client erhält ein Synchronisierungstoken, das dauerhaft gespeichert werden muss.

  2. Die inkrementelle Synchronisierung wird wiederholt durchgeführt und aktualisiert den Client mit allen seit der letzten Synchronisierung vorgenommenen Änderungen. Jedes Mal stellt der Client das vorherige Synchronisierungstoken bereit, das er vom Server erhalten hat, und speichert das neue Synchronisierungstoken aus der Antwort.

Erste vollständige Synchronisierung

Die erste vollständige Synchronisierung ist die ursprüngliche Anfrage an alle Ressourcen der Sammlung, die Sie synchronisieren möchten. Sie können die Listenanfrage optional mithilfe von Anfrageparametern einschränken, wenn Sie nur einen bestimmten Teil der Ressourcen synchronisieren möchten.

In der Antwort auf den Listenvorgang finden Sie ein Feld namens nextSyncToken, das ein Synchronisierungstoken darstellt. Sie müssen den Wert von nextSyncToken speichern. Wenn die Ergebnismenge zu groß ist und die Antwort mit Seitenzahlen versehen wird, ist das Feld nextSyncToken nur auf der letzten Seite vorhanden.

Inkrementelle Synchronisierung

Mit der inkrementellen Synchronisierung können Sie alle Ressourcen abrufen, die seit der letzten Synchronisierungsanfrage geändert wurden. Dazu müssen Sie eine Listenanfrage ausführen und dabei das letzte Synchronisierungstoken im Feld syncToken angeben. Denken Sie daran, dass das Ergebnis immer gelöschte Einträge enthält, sodass die Clients diese aus dem Speicher entfernen können.

Wenn sich eine große Anzahl von Ressourcen seit der letzten inkrementellen Synchronisierungsanfrage geändert hat, wird im Listenergebnis möglicherweise ein pageToken anstelle von syncToken angezeigt. In diesen Fällen müssen Sie genau die gleiche Listenabfrage ausführen, die zum Abrufen der ersten Seite in der inkrementellen Synchronisierung verwendet wurde (mit genau demselben syncToken). Danach müssen Sie pageToken anhängen und alle folgenden Anfragen durchgehen, bis auf der letzten Seite eine weitere syncToken gefunden wird. Achten Sie darauf, dass Sie diese syncToken für die nächste Synchronisierungsanfrage speichern.

Hier sind Beispielabfragen für einen Fall, der eine inkrementelle nummerierte Synchronisierung erfordert:

Ursprüngliche Abfrage

GET /calendars/primary/events?maxResults=10&singleEvents=true&syncToken=CPDAlvWDx70CEPDAlvWDx

// Result contains the following

"nextPageToken":"CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA",

Nächste Seite abrufen

GET /calendars/primary/events?maxResults=10&singleEvents=true&syncToken=CPDAlvWDx70CEPDAlvWDx&pageToken=CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA

Vollständige Synchronisierung durch Server erforderlich

Manchmal werden Synchronisierungstokens vom Server aus verschiedenen Gründen ungültig, z. B. aufgrund des Ablaufs von Tokens oder aus Änderungen an zugehörigen ACLs. In solchen Fällen antwortet der Server auf eine inkrementelle Anfrage mit dem Antwortcode 410. Dies sollte eine vollständige Löschung des Client-Speichers und eine neue vollständige Synchronisierung auslösen.

Beispielcode

Das folgende Codebeispiel zeigt, wie Synchronisierungstokens mit der Java-Clientbibliothek verwendet werden. Beim ersten Aufruf der Ausführungsmethode wird eine vollständige Synchronisierung durchgeführt und das Synchronisierungstoken gespeichert. Bei jeder nachfolgenden 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 kann die Synchronisierung weiterhin auf alte Weise durchgeführt werden. 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 in Bezug auf verpasste Aktualisierungen fehleranfälliger ist (z. B. wenn Abfrageeinschränkungen nicht erzwungen werden). Außerdem ist sie nur für Veranstaltungen verfügbar.