Ressourcen effizient synchronisieren

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 Bandbreite sparen.

Inhalt

Überblick

Die inkrementelle Synchronisierung besteht aus zwei Phasen:

  1. Die anfängliche vollständige Synchronisierung wird 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 beibehalten werden muss.

  2. Die inkrementelle Synchronisierung wird wiederholt ausgeführt und aktualisiert den Client mit allen Änderungen, die seit der letzten Synchronisierung vorgenommen wurden. 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 für alle Ressourcen der Sammlung, die Sie synchronisieren möchten. Wenn Sie nur eine bestimmte Teilmenge von Ressourcen synchronisieren möchten, können Sie die Listenanfrage optional mithilfe von Anfrageparametern einschränken.

In der Antwort auf den list-Vorgang 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 paginiert 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. Geben Sie dabei Ihr neuestes Synchronisierungstoken im Feld syncToken an. Beachten Sie, dass das Ergebnis immer gelöschte Einträge enthält, sodass die Clients die Möglichkeit haben, diese aus dem Speicher zu entfernen.

Wenn sich seit der letzten inkrementellen Synchronisierungsanfrage eine große Anzahl von Ressourcen geändert hat, wird in der Ergebnisliste 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 der inkrementellen Synchronisierung verwendet wurde (mit genau demselben syncToken), das pageToken anhängen und alle folgenden Anfragen durchgehen, bis Sie auf der letzten Seite eine weitere syncToken finden. Achten Sie darauf, diese syncToken für die nächste Synchronisierungsanfrage in Zukunft zu speichern.

Hier sind Beispielabfragen für einen Fall, bei dem eine inkrementelle Synchronisierung mit nummerierten Seiten erforderlich ist:

Ursprüngliche Anfrage

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. aus dem Ablauf von Tokens oder Änderungen in 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 Clientspeichers und eine neue vollständige Synchronisierung auslösen.

Beispielcode

Das folgende Beispielcode-Snippet veranschaulicht, 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

Für Ereignissammlungen ist eine Legacy-Synchronisierung weiterhin möglich. Dabei wird der Wert des aktualisierten Felds aus einer Ereignislistenanfrage beibehalten und dann mit dem Feld modifiedSince aktualisierte Ereignisse abgerufen. Dieser Ansatz wird nicht mehr empfohlen, da er in Bezug auf verpasste Aktualisierungen fehleranfälliger ist (z. B. wenn keine Abfrageeinschränkungen erzwungen werden). Außerdem ist sie nur für Veranstaltungen verfügbar.