Sync from several threads or processes#

One Replica serves every thread of a process, and a SQLite store serves every process on the machine.

Sync scopes at once#

from concurrent.futures import ThreadPoolExecutor

with ThreadPoolExecutor() as pool:
    for done in [pool.submit(adapter.sync) for adapter in adapters]:
        done.result()

Each adapter syncs its own scope, so they run side by side. The store runs one write at a time, with reads beside it. Sync a scope from one thread at a time: a second sync of the same scope in the same process raises SessionError. Your application’s reads don’t wait for a sync, as StateStore describes.

Share a store between processes#

from calendaring_sync import StaleChangeSetError


def sync(adapter, attempts=3):
    """Sync once, again if another process ingested the scope first."""
    for _ in range(attempts - 1):
        try:
            return adapter.sync()
        except StaleChangeSetError:
            pass
    return adapter.sync()


for adapter in adapters:
    sync(adapter)

Each process opens the store file itself and makes its own replica. When two processes sync one scope at the same moment, the one that ingests second gets StaleChangeSetError and nothing changes, so syncing again is enough. Design explains why that’s safe, and the rare case where one edit is sent twice.

Last updated on 2026-10-27.