高效同步资源

本指南介绍了如何 实现“增量同步”大量日历数据使用此 方法,您可以在保存时同步所有日历集合的数据 带宽。

目录

概览

增量同步包含两个阶段:

  1. 初始完全同步从一开始执行一次,以便完全 将客户端的状态与服务器的状态同步。客户端将获得 需要持久保留的同步令牌

  2. 增量同步会重复执行,并使用所有 自上次同步以来发生的更改。每次 用于提供从服务器获取的上一个同步令牌,并存储响应中的新同步令牌。

首次完全同步

初始完全同步是对 每个您想要同步的集合您可以选择限制列表 使用请求参数发出请求 一部分资源

在对 list 操作的响应中,您会看到一个名为 表示同步令牌的 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 客户端库。第一次 系统会调用 run 方法,该方法将执行完全同步并存储同步令牌。 后续每次执行时,系统都会加载已保存的同步令牌,并执行 增量同步。

  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 字段检索更新后的事件。 我们不再推荐使用此方法,因为它在 错过的更新(例如,如果不强制执行查询限制)。 此外,它仅可用于活动。