효율적으로 리소스 동기화

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

이 가이드에서는 캘린더 데이터의 '증분 동기화'를 구현하는 방법을 설명합니다. 이 방법을 사용하면 대역폭을 절약하는 동시에 모든 캘린더 컬렉션의 데이터를 동기화할 수 있습니다.

목차

개요

증분 동기화는 다음 두 단계로 구성됩니다.

  1. 초기 전체 동기화는 클라이언트의 상태를 서버의 상태와 완전히 동기화하기 위해 맨 처음 한 번 수행됩니다. 클라이언트는 유지해야 하는 동기화 토큰을 얻습니다.

  2. 증분 동기화가 반복적으로 수행되며 이전 동기화 이후 발생한 모든 변경사항으로 클라이언트를 업데이트합니다. 매번 클라이언트는 서버에서 가져온 이전 동기화 토큰을 제공하고 응답의 새 동기화 토큰을 저장합니다.

초기 전체 동기화

초기 전체 동기화는 동기화하려는 컬렉션의 모든 리소스에 대한 원래 요청입니다. 특정 리소스 하위 집합만 동기화하려는 경우 요청 매개변수를 사용하여 선택적으로 목록 요청을 제한할 수 있습니다.

목록 작업에 대한 응답으로 동기화 토큰을 나타내는 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로 증분 요청에 응답합니다. 이렇게 하면 클라이언트 스토어가 완전히 완전 삭제되고 새로운 전체 동기화가 트리거됩니다.

샘플 코드

아래의 샘플 코드 스니펫은 자바 클라이언트 라이브러리와 동기화 토큰을 사용하는 방법을 보여줍니다. 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 필드를 사용하여 업데이트된 이벤트를 검색하여 기존 방식으로 동기화를 수행할 수 있습니다. 이 방법은 누락된 업데이트 (예: 쿼리 제한을 적용하지 않는 경우)와 관련하여 오류가 발생하기 쉬우므로 더 이상 권장되지 않습니다. 또한 이벤트에만 사용할 수 있습니다.