Эффективная синхронизация ресурсов

В этом руководстве описывается, как реализовать инкрементную синхронизацию данных календаря. Этот метод позволяет синхронизировать данные для всех коллекций календарей, экономя пропускную способность.

Содержание

Обзор

Добавочная синхронизация состоит из двух этапов:

  1. Первоначальная полная синхронизация выполняется один раз в самом начале, чтобы полностью синхронизировать состояние клиента с состоянием сервера. Клиент получит токен синхронизации, который ему нужно сохранить.

  2. Инкрементная синхронизация выполняется многократно и обновляет клиент, добавляя все изменения, произошедшие с момента предыдущей синхронизации. Каждый раз клиент предоставляет предыдущий токен синхронизации, полученный от сервера, и сохраняет новый токен синхронизации из ответа.

Первая полная синхронизация

Первоначальная полная синхронизация – это исходный запрос всех ресурсов коллекции, которую вы хотите синхронизировать. Если вы хотите синхронизировать только определенный набор ресурсов, вы можете ограничить запрос списка с помощью параметров запроса.

В ответе на операцию list вы найдете поле nextSyncToken, представляющее токен синхронизации. Вам нужно будет сохранить значение nextSyncToken. Если набор результатов слишком велик и ответ разбивается на страницы, то поле nextSyncToken присутствует только на последней странице.

Инкрементная синхронизация

Инкрементная синхронизация позволяет получить все ресурсы, которые были изменены с момента последнего запроса на синхронизацию. Для этого нужно выполнить запрос списка, указав в поле syncToken последний токен синхронизации. Помните, что результат всегда будет содержать удаленные записи, чтобы клиенты могли удалить их из хранилища.

Если с момента последнего запроса на инкрементную синхронизацию изменилось большое количество ресурсов, в результатах списка вместо syncToken может появиться pageToken. В таких случаях вам нужно будет выполнить точно такой же запрос списка, который использовался для получения первой страницы при добавочной синхронизации (с точно таким же 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

Сервер требует полной синхронизации.

Иногда сервер аннулирует токены синхронизации по разным причинам, например из-за истечения срока действия токена или изменений в связанных списках управления доступом. В таких случаях сервер ответит на запрос кодом 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 для получения обновленных событий. Этот подход больше не рекомендуется, поскольку он чаще приводит к ошибкам, связанным с пропущенными обновлениями (например, если он не применяет ограничения на запросы). Кроме того, он доступен только для мероприятий.