Read the change feed#

The change feed lists every change syncs made to the store, every conflict resolved and every scope dropped. Keep a cursor, the number of the last entry you handled, and read the entries after it.

Read from a cursor#

from pathlib import Path

from calendaring_sync import TrimmedFeedError

CURSOR = Path("feed-cursor.txt")

cursor = int(CURSOR.read_text()) if CURSOR.exists() else 0
try:
    while entries := replica.read_feed(after=cursor):
        for entry in entries:
            handle(entry)
        cursor = entries[-1].number
        CURSOR.write_text(str(cursor))
except TrimmedFeedError:
    reload_everything()
    CURSOR.write_text(str(replica.feed_head()))

handle and reload_everything are your application’s. The example reads the cursor before a pass and saves it after each page. A crash between the two replays that page instead of skipping it, so make handle safe to call twice for one entry. Each part of your application that reads the feed keeps a cursor of its own.

The except branch handles a cursor older than what the feed keeps, as TrimmedFeedError describes.

Trim and purge#

replica.trim_feed(through=cursor)
replica.purge(through=cursor)

The feed and the removed records grow until you trim and purge them. Pass the lowest cursor any part of your application still reads from. trim_feed() deletes the entries up to it, and purge() deletes the records removed by then.

Last updated on 2026-10-27.