만료 행 정리의 500행 배치 한계: 유지보수 성공 뒤 남는 backlog

이 글의 목차 6개 항목
  • 분야: DB
  • 기술 스택: TypeScript · SQLite · Cloudflare D1

문제와 원인

현재 만료 행 정리 함수는 테이블마다 최대 500행을 한 번 삭제하고 반환한다. 만료 이벤트가 500행을 넘으면 유지보수 작업이 정상 종료해도 backlog가 남는다.

현재 코드

cleanupExpiredRows

이벤트 삭제는 다음 배치 크기와 SQL을 사용한다.

const CLEANUP_BATCH_SIZE = 500;
DELETE FROM analytics_events
WHERE id IN (
  SELECT id FROM analytics_events
  WHERE occurred_at < datetime('now', ?)
  ORDER BY occurred_at, id LIMIT ?
);

보관기간 90일의 매개변수는 -90 days와 500이다. 감사 로그와 시스템 오류도 같은 방식으로 한 배치씩 정리하고, 게스트 세션 두 테이블에는 별도 만료 조건을 적용한다.

runOperationalMaintenance

유지보수 호출부는 정리 함수를 한 번 호출한 뒤 백업과 완료 처리를 진행한다.

const retentionDays = await repository.analyticsRetentionDays();
const cleanup = await repository.cleanupExpiredRows(retentionDays);
const backup = await maybeCreateAutomaticBackup({
  email: "scheduled-maintenance@baeumzip.local",
  hash: "scheduled-maintenance",
});
await repository.completeLease(TASK, owner);

일일 예약 워크플로는 자동 백업의 진행 응답 202에 따라 유지보수 POST를 반복할 수 있다. 삭제량은 호출당 500행이며 하루 호출 수는 백업 진행에 따라 달라진다. 정리 함수 자체는 만료 행을 끝까지 삭제하는 반복 없이 반환한다.

진단 결과

합성 이벤트 정리

Node.js, SQLite의 메모리 DB에 100일 전 만료 이벤트 500·1,500·50,000행과 1일 전 새 이벤트 1행을 넣었다. 감사·오류·게스트 세션 테이블은 비운 상태에서 cleanupExpiredRows(90)를 각 규모별 1회 호출하고 잔여량을 조회했다. 이어 같은 함수를 직접 반복 호출해 만료 행이 0이 될 때까지의 총 호출 수를 기록했다.

만료 입력첫 호출 삭제첫 호출 뒤 만료 잔여량만료 행을 비우는 총 호출 수새 행 보존
500행500행0행1회1행
1,500행500행1,000행3회1행
50,000행500행49,500행100회1행

Chrome의 SQLite Fiddle 3.54.0에서도 고정 seed SQL로 만료 1,500행과 새 행 1행을 만든 뒤 위 이벤트 DELETE를 1회 실행했다.

조회 항목DELETE 전DELETE 후
전체 행1,501행1,001행
만료 행1,500행1,000행
새 행1행1행
changes()—500행

DELETE 전 조회는 전체 1,501행 중 만료 1,500행·새 행 1행을 반환했다.

DELETE 전: 전체 1,501행·만료 1,500행·새 행 1행원본 보기 (새 창)

DELETE 전: 전체 1,501행·만료 1,500행·새 행 1행

100%원본 보기 (새 창)

확대한 이미지는 상하좌우로 이동할 수 있습니다. 키보드는 이미지 영역에 초점을 두고 방향키를 사용하세요. Esc로 닫습니다.

DELETE를 1회 실행한 뒤 changes()는 500행이었다. 만료 행은 1,000행이 남았고 새 행 1행은 유지됐다.

DELETE 후: 500행 삭제·만료 1,000행 잔여·새 행 보존원본 보기 (새 창)

DELETE 후: 500행 삭제·만료 1,000행 잔여·새 행 보존

100%원본 보기 (새 창)

확대한 이미지는 상하좌우로 이동할 수 있습니다. 키보드는 이미지 영역에 초점을 두고 방향키를 사용하세요. Esc로 닫습니다.