Эффективно синхронизируйте ресурсы

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

Содержание

Обзор

Инкрементная синхронизация состоит из двух этапов:

  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

Требуется полная синхронизация с сервером

Иногда токены синхронизации становятся недействительными на сервере по разным причинам, включая истечение срока действия токена или изменение связанных списков контроля доступа (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.");
  }

Устаревшая синхронизация

Для коллекций событий по-прежнему можно выполнить синхронизацию традиционным способом, сохраняя значение поля updated из запроса списка событий и затем используя поле modifiedSince для извлечения обновлённых событий. Этот подход больше не рекомендуется, поскольку он более подвержен ошибкам, связанным с пропущенными обновлениями (например, если не применяются ограничения запроса). Более того, он доступен только для событий.