증분 수집의 마지막 시각: 동률·LIMIT·삭제와 동기화 토큰

이 카테고리 글 목록

전체글 보기

‘마지막으로 받은 updated_at보다 큰 자료만 읽기’로 증분 수집을 만들었다면 같은 시각의 자료가 페이지 경계에 걸릴 때 빠질 수 있다. 한 시각의 일부를 받은 상태와 그 시각의 모든 자료를 처리한 상태를 구별하고, 다음 실행의 진행 위치를 그 계약에 맞게 저장해야 한다. 삭제가 목록에서 사라지는 서비스라면 수정 시각만으로는 삭제 사실도 알아낼 수 없다.

이 글의 A~F, 시각 숫자10~12와 토큰 S0·S1은 설명용 가상 값이다. 로컬 Python에서 입력·출력을 확인했으며 실제 Google 계정·일정, 운영 DB·동기화 서비스에 접근하지 않았다.

같은 시각 A·B·C 중 두 건만 받으면 C가 남는다

입력은 A/10, B/10, C/10, D/11, E/12이고, 시각과 ID 오름차순으로 최대 두 건씩 받는다고 하자. 첫 실행이 시각9보다 큰 자료에서 A·B만 받았는데 워터마크를10으로 올리면, 다음의 ‘시각>10’은D·E를 반환한다. 최종 수집은 A·B·D·E이며C가 빠진다.

# (ID, updated_at): 고정된 가상 자료, 실제 API 응답이 아니다.
rows = [('A', 10), ('B', 10), ('C', 10), ('D', 11), ('E', 12)]
rows = sorted(rows, key=lambda r: (r[1], r[0]))
first = [r for r in rows if r[1] > 9][:2]
watermark = first[-1][1]
second = [r for r in rows if r[1] > watermark][:2]
# first == [('A', 10), ('B', 10)]
# second == [('D', 11), ('E', 12)]

마지막 수신 시각을 최대값으로 저장했다는 사실만으로 동률 그룹을 모두 읽었다고 할 수 없다. 본문에서의 시각 숫자는 단순 비교를 위한 값이며 실제 타임스탬프 정밀도·시간대나 서비스 시계 규칙을 검증한 결과는 아니다.

같은 평가 카드가 청록색과 노란색 두 목록으로 나뉘고 돋보기로 실패 카드를 살펴보는 삽화
같은 자료와 두 결과를 대조하는 기존 AI 생성 개념도. 단일 시각 경계와 조건을 갖춘 진행 위치에서 모인 ID를 비교하는 맥락이다. 실제 동기화 화면·토큰 구조나 시간별 누락 도표는 아니다.

복합 진행 위치와 포함 재수집도 조건이 필요하다

후보 동률에서 필요한 조건 그것만으로 안 되는 것
시각+유일 ID 같은 완전 정렬·복합 비교 위치 앞의 지연 도착
경계 포함 재수집 경계 구간 전체 순회·버전 대조 같은 LIMIT 반복의 정체
제품의 sync token 페이지·필터·삭제 계약 준수 임의 시각으로의 대체

고정된 위 자료를 (시각,ID) 순서로 읽고 마지막 위치(10,B)보다 큰 쌍부터 이어가면 다음은C·D, 그 뒤는E였다. 이 후보는 서버가 같은 정렬과 복합 조건을 지원하고 해당 키의 유일성·비교 규칙이 정해졌을 때 검토할 수 있다. 불투명 API 토큰을 마음대로 이 쌍으로 바꾼다는 뜻은 아니다.

‘시각>=10’으로 포함해 다시 읽는 방식도 두 건 LIMIT을 그대로 반복하면 매번A·B만 받을 수 있다. 경계 구간을 별도로 끝까지 열거하고, 같은 ID의 재수정은 문서화된 버전·내용으로 대조할 조건이 필요하다. 이번 합성 확인은 고정 구간 전체를 읽어 ID별로 합치면A~E가 남는다는 결과이며 모든 변경 이력을 보존하는 알고리즘은 아니다.

최종 위치가(12,E)여도 나중에 시각9의F가 도착하면 복합 ‘>’ 조건 밖이다. 지연 도착, 시각 되돌림, 이미 읽은 ID의 재수정, 삭제까지 두 후보가 자동으로 해결하지 않는다. 허용된 재대조 창과 원본의 변경·삭제 전달 규칙을 별도로 확인한다. 조회 중 목록 자체의 변화는 offset·정렬·snapshot의 차이와도 연결된다.

Calendar에서는 페이지 토큰과 다음 동기화 토큰을 나눈다

Google Calendar의 증분 동기화 안내는 최초 전체 동기화와 이후 증분 동기화를 나눈다. 페이지가 더 있으면 이어 읽고, 마지막 페이지에서 받은 nextSyncToken을 다음 동기화에 사용한다. 증분 응답도 여러 페이지라면 같은 syncToken과 같은 조회 조건에 pageToken을 붙여 끝까지 읽는다.

Events.list 계약은 nextPageToken과 nextSyncToken을 구별하며, syncToken과 함께 쓸 수 없는 필터가 있고 다른 매개변수도 최초 동기화와 같아야 한다고 명시한다. 시각 필터 updatedMin을 기존 syncToken에 임의로 덧붙이거나 토큰을 수정 시각으로 해석하지 않는다. 이는 Calendar 제품의 계약이며 모든 cursor API의 공통 규칙이 아니다.

가상 로컬 복제본에A v1과B v1, 진행 토큰S0가 있다고 하자. 첫 응답이A v2와 다음 페이지P2만 주고, 두 번째가B의 삭제 표시와 다음 동기화 토큰S1을 준다면, 첫 응답에서 이번 변경 수집을 완료했다고 하면B가 남는다. 로컬 모델에서는 두 페이지의 변경을 반영한 뒤A v2만 남고 진행 토큰을S1로 바꿨다. 여기의 deleted 플래그는 설명용 정규화이며 Calendar의 실제 이벤트 스키마나 반복 일정 취소 처리 코드를 구현한 것이 아니다.

삭제와 무효 토큰을 성공한 빈 결과로 덮지 않는다

Calendar 증분 응답은 삭제된 항목도 포함하며 Events.list는 syncToken 사용 시 showDeleted를False로 지정할 수 없다고 한다. 삭제·취소 표시의 세부 의미와 반복 일정 예외는 해당 이벤트 계약에 맞춰 처리해야 한다. 단순히 응답에서 안 보이는 ID를 전부 삭제하는 방법과는 다르다.

문서화된410 무효 토큰 응답에서는 해당 동기화용 로컬 저장소를 비우고 새 전체 동기화를 하도록 안내한다. 이는 원본 일정을 삭제하라는 뜻이 아니다. 마지막 정상 토큰·오류·복제 범위를 구별하고 제품이 정한 재동기화로 돌아가야 한다. 이 글에서는 실제410이나 계정 자료, 운영 저장소 초기화를 시험하지 않았다.

작성자는 변경 내용의 저장·삭제 반영과 진행 위치의 저장이 어긋나지 않게 하고, 중간 실패가 있으면 이미 반영한 범위와 남은 페이지를 구별할 것을 제안한다. 원자적 저장 또는 재처리 가능성은 쓰는 저장소와 제품 계약에서 확인할 사항이지 이번 작은 모델의 보장이 아니다.

수집 성공과 페이지 끝 자체는 전체 목록과 수집 범위 확인, 원본 변경 이후 검색에 보이는 시간차는 RAG 갱신·인덱싱 병목으로 구별한다. 불확실한 외부 쓰기를 다시 보내는 문제는 재시도 정책의 안전 조건에 해당하며 이 글의 pull 진행 경계와 같지 않다.

자주 묻는 질문

시각에 ID를 붙이면 지연 도착도 다 잡히나요?

이미 지난 복합 위치보다 앞에 도착한 자료는 빠질 수 있다. 원본의 시각 의미·변경 피드·재대조 범위와 정렬 키 변경 조건을 따로 확인한다.

이미 본 ID는 모두 버려도 되나요?

같은 ID에도 새 버전이나 삭제 표시가 올 수 있다. 존재 여부만으로 버리지 않고 제품이 제공한 변경·버전 계약과 저장 목적에 맞게 대조한다.

마지막 페이지 토큰과 sync token은 같은 값인가요?

Calendar에서는 역할이 다르다. 다음 페이지 위치와 이후 동기화의 기준 토큰을 구분하고, 최종 페이지의 변경을 필요한 범위까지 반영한 상태와 함께 진행을 기록한다. 다른 제품은 그 제품 문서를 따른다.

이 카테고리의 다른 글

전체글 보기

댓글 남기기