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

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

Содержание

Обзор

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

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

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

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

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

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