Sincronizar recursos com eficiência

Este guia descreve como implementar a "sincronização incremental" de dados da agenda. Com esse método, você pode manter os dados de todas as coleções de agendas sincronizados e economizar a largura de banda.

Conteúdo

Visão geral

A sincronização incremental consiste em dois estágios:

  1. A sincronização completa inicial é realizada uma vez no início para sincronizar totalmente o estado do cliente com o do servidor. O cliente receberá um token de sincronização que precisa ser mantido.

  2. A sincronização incremental é executada repetidamente e atualiza o cliente com todas as mudanças que ocorreram desde a sincronização anterior. Toda vez, o cliente fornece o token de sincronização anterior recebido do servidor e armazena o novo token de sincronização a partir da resposta.

Sincronização completa inicial

A sincronização completa inicial é a solicitação original de todos os recursos da coleção que você quer sincronizar. Você poderá restringir a solicitação de lista usando parâmetros de solicitação se quiser sincronizar apenas um subconjunto específico de recursos.

Na resposta à operação de lista, você encontrará um campo chamado nextSyncToken, que representa um token de sincronização. Você vai precisar armazenar o valor de nextSyncToken. Se o conjunto de resultados for muito grande e a resposta for paginada, o campo nextSyncToken estará presente apenas na última página.

Sincronização incremental

A sincronização incremental permite recuperar todos os recursos que foram modificados desde a última solicitação de sincronização. Para fazer isso, é necessário executar uma solicitação de lista com o token de sincronização mais recente especificado no campo syncToken. Lembre-se de que o resultado sempre conterá entradas excluídas, para que os clientes tenham a chance de removê-las do armazenamento.

Nos casos em que um grande número de recursos mudou desde a última solicitação de sincronização incremental, é possível encontrar uma pageToken em vez de uma syncToken no resultado da lista. Nesses casos, será necessário executar a mesma consulta de lista usada para a recuperação da primeira página na sincronização incremental (com exatamente o mesmo syncToken), anexe o pageToken a ela e faça a paginação de todas as solicitações a seguir até encontrar outro syncToken na última página. Armazene esse syncToken para a próxima solicitação de sincronização no futuro.

Veja alguns exemplos de consultas para um caso que requer sincronização paginada incremental:

Consulta original

GET /calendars/primary/events?maxResults=10&singleEvents=true&syncToken=CPDAlvWDx70CEPDAlvWDx

// Result contains the following

"nextPageToken":"CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA",

Recuperando a próxima página

GET /calendars/primary/events?maxResults=10&singleEvents=true&syncToken=CPDAlvWDx70CEPDAlvWDx&pageToken=CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA

Sincronização completa exigida pelo servidor

Às vezes, os tokens de sincronização são invalidados pelo servidor por vários motivos, incluindo expiração do token ou alterações nas ACLs relacionadas. Nesses casos, o servidor responderá a uma solicitação incremental com um código de resposta 410. Isso deve acionar uma exclusão completa da loja do cliente e uma nova sincronização completa.

Exemplo de código

O snippet do exemplo de código abaixo demonstra como usar tokens de sincronização com a biblioteca de cliente Java. Na primeira vez que o método de execução é chamado, ele realiza uma sincronização completa e armazena o token de sincronização. Em cada execução subsequente, ele vai carregar o token de sincronização salvo e realizar uma sincronização incremental.

  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.");
  }

Sincronização legada

Para coleções de eventos, ainda é possível fazer a sincronização da maneira legada preservando o valor do campo atualizado de uma solicitação de lista de eventos e usando o campo modifiedSince para recuperar eventos atualizados. Essa abordagem não é mais recomendada porque é mais propensa a erros em relação a atualizações perdidas (por exemplo, se não aplicar restrições de consulta). Além disso, está disponível apenas para eventos.