Skip to content

DatabaseWrapper observation is per-clone, not per-database — writes through sibling clones are silently unobserved #53

Description

@yokuze

DatabaseWrapper is #[derive(Clone)] and all clones share one underlying write
connection, but observation is stored in a per-value observer: Option<ObservableSqliteDatabase> field. enable_observation() therefore turns
observation on for the handle it is called on only — a sibling clone keeps observer: None, so its acquire_writer() returns the regular (bypass) writer, and a committed
write through it fires no hooks and reaches no subscriber. No error, no warning.

This bites any Tauri consumer that observes via a clone. app.connect(key) (and the JS
Database.load(key)) hand out clones of the plugin's cached wrapper, so a Rust consumer
that does app.connect(key)enable_observation()subscribe() silently misses
writes made through every other app.connect(key) clone (command handlers, background
tasks). The only handle whose observation later clones inherit is the cached entry itself,
which is mutated solely by the JS observe command — unreachable from Rust callers, since
the instance cache is private to the crate.

Repro

Minimal, runnable repro (cargo run, prints an explicit verdict; includes a control that
proves the probe detects real notifications):
https://github.com/yokuze/mcve/tree/23aa4a2acc7e0956ba499751770d4c54b9451da1/cases/003-sqlx-sqlite-toolkit-observation-not-shared-across-clones

Root cause (rev e1b3836)

Expected

Observation should apply to the database, not to one handle — e.g. store the observer
behind shared interior state so that enabling it on any clone makes all clones (existing
and future) observe the same broker, or at minimum make a bypassed write on a database
observed elsewhere detectable instead of silently dropped.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions