Skip to content

sync_roundtrip test fails on Windows with DatabaseBusy on journal_mode=WAL (tmp-file collision + missing busy_timeout) #664

Description

@ErikBjare

aw-sync/tests/sync_roundtrip.rs::test_own_data_does_not_return_via_peer (added in #648) fails on Windows in the activitywatch bundle CI, and today it went from occasionally-flaky to reliably failing (2/2 runs, each already wrapped in a retry action):

thread '<unnamed>' panicked at aw-datastore\src\worker.rs:155:14:
Failed to query journal_mode: SqliteFailure(Error { code: DatabaseBusy, extended_code: 5 }, Some("database is locked"))
thread 'test_own_data_does_not_return_via_peer' panicked at aw-sync\tests\sync_roundtrip.rs:72:10:
called `Result::unwrap()` on an `Err` value: InternalError("Failed to receive response, datastore worker died while handling request: RecvError")

Evidence it's environmental timing rather than a code regression: the bundle pin (b2e2dee) is unchanged since 2026-08-20, the same job passed on 2026-08-27, and this repo's own Windows CI was green at #648 merge time and on recent master. Something in the runner environment shifted the timing enough to make the race land consistently.

Two candidate mechanisms, both worth fixing:

  1. tmp filename collisions across parallel tests. tmp_db() builds uniqueness from process::id() + name + SystemTime nanos. Cargo runs the tests in the same process on parallel threads, and each test uses the same name values (a-local, a-export, ...). If two tests hit the same clock tick, they open the same db file from two datastore workers; the second journal_mode=WAL pragma needs an exclusive lock and dies with SQLITE_BUSY. Fix: add a per-call AtomicUsize counter to the filename (or use tempfile).

  2. No busy_timeout on any connection. git grep busy_timeout comes up empty. The WAL pragma at worker.rs:155 runs with rusqlite's default (no busy handler), so any transient holder of the file — including Windows Defender scanning a freshly created file, a well-known Windows CI failure mode — is an instant panic rather than a short wait. Setting conn.busy_timeout(Duration::from_secs(5)) before the pragmas makes open robust. This is also production-relevant: any tool opening a datastore file that briefly overlaps with another handle (e.g. aw-sync touching an export while a checkpoint runs) currently panics the worker instead of waiting.

Suggest doing both: (1) fixes the test correctness, (2) fixes the class of failure.

Context: found while chasing red master CI on ActivityWatch/activitywatch (run 33269017968, Windows Qt job, both attempts).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions