Summary
DownloadClient::run acquires the PowerSync SQLite writer before calling DownloadEvent::invoke_control, then keeps that lease while handling every returned instruction. An EstablishSyncStream instruction subsequently awaits connector.fetch_credentials() and creates the HTTP stream.
Root cause
A credentials provider may be slow or may need local database work. Holding the SDK's single writer across those awaits blocks unrelated local writes and can create a wait cycle. The writer is required only to invoke powersync_control and obtain the instructions; it is not required to interpret or execute the resulting SDK-side instructions.
Expected behavior
Release the writer immediately after invoke_control returns. Processing EstablishSyncStream may then await credential retrieval and network setup without owning the writer.
Deterministic regression
A connector can deliberately pause in fetch_credentials(). While paused, a separate db.writer() acquisition should complete. It does not on current main, because the download client retains the lease.
This is separate from #19, #21, and #22: it concerns the download actor's async scope, not statement cleanup at a pool boundary or a new transaction API.
Summary
DownloadClient::runacquires the PowerSync SQLite writer before callingDownloadEvent::invoke_control, then keeps that lease while handling every returned instruction. AnEstablishSyncStreaminstruction subsequently awaitsconnector.fetch_credentials()and creates the HTTP stream.Root cause
A credentials provider may be slow or may need local database work. Holding the SDK's single writer across those awaits blocks unrelated local writes and can create a wait cycle. The writer is required only to invoke
powersync_controland obtain the instructions; it is not required to interpret or execute the resulting SDK-side instructions.Expected behavior
Release the writer immediately after
invoke_controlreturns. ProcessingEstablishSyncStreammay then await credential retrieval and network setup without owning the writer.Deterministic regression
A connector can deliberately pause in
fetch_credentials(). While paused, a separatedb.writer()acquisition should complete. It does not on currentmain, because the download client retains the lease.This is separate from #19, #21, and #22: it concerns the download actor's async scope, not statement cleanup at a pool boundary or a new transaction API.