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 synchronisieren und gleichzeitig Bandbreite sparen.

Inhalt

Übersicht

Die inkrementelle Synchronisierung besteht aus zwei Phasen:

  1. Die erste vollständige Synchronisierung wird einmal 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 er speichern 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. Sie können die Listenanfrage optional mit Anfrageparametern einschränken, wenn Sie nur eine bestimmte Teilmenge von Ressourcen synchronisieren möchten.

In der Antwort auf den Listen-Vorgang finden Sie ein Feld namens nextSyncToken, das ein Synchronisierungstoken darstellt. Sie müssen den Wert von nextSyncToken speichern. Wenn das Ergebnis-Set zu groß ist und die Antwort mit Seitenumbrüchen 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 mit Ihrem letzten Synchronisierungstoken im Feld syncToken senden. 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, finden Sie im Listenergebnis möglicherweise ein pageToken anstelle eines syncToken. In diesen Fällen müssen Sie genau dieselbe Listenabfrage wie beim Abrufen der ersten Seite in der inkrementellen Synchronisierung (mit genau demselben syncToken) ausführen, das pageToken anhängen und alle nachfolgenden Anfragen durchlaufen, bis Sie auf der letzten Seite ein weiteres syncToken finden. Speichere diese syncToken für die nächste Synchronisierungsanfrage.

Hier sind Beispielanfragen für einen Fall, der eine inkrementelle paginierte Synchronisierung erfordert:

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 durch Server erforderlich

Manchmal werden Synchronisierungstokens aus verschiedenen Gründen vom Server ungültig gemacht, z. B. weil sie abgelaufen sind oder sich die zugehörigen ACLs geändert haben. In solchen Fällen antwortet der Server auf eine inkrementelle Anfrage mit dem Antwortcode 410. Dadurch sollte der Speicher des Kunden vollständig gelöscht und eine neue vollständige Synchronisierung ausgelöst werden.

Beispielcode

Das folgende Beispielcode-Snippet zeigt, wie Synchronisierungstokens mit der Java-Clientbibliothek verwendet werden. Wenn die Methode „run“ zum ersten Mal aufgerufen wird, wird eine vollständige Synchronisierung durchgeführt und das Synchronisierungstoken wird 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.");
  }

Alte Synchronisierung

Bei Ereignissammlungen ist die Synchronisierung weiterhin auf die alte Weise möglich. Dazu wird der Wert des aktualisierten Felds aus einer Ereignislistenanfrage beibehalten und dann das Feld modifiedSince verwendet, um aktualisierte Ereignisse abzurufen. Diese Methode wird nicht mehr empfohlen, da sie anfälliger für Fehler ist, z. B. wenn keine Abfragebeschränkungen erzwungen werden. Außerdem ist sie nur für Ereignisse verfügbar.