Skip to content

Re-calling observe()/enable_observation() silently terminates existing subscribers #54

Description

@yokuze

enable_observation() calls disable_observation() first, dropping the previous
ObservableSqliteDatabase and its broadcast broker. The broker owns the only
broadcast::Sender, so every Receiver handed out earlier gets RecvError::Closed on its
next recv() — the change stream just ends, with no error attributable to a cause and no
notification to whoever set up that subscription.

The crate-level behavior is documented ("the previous observer is disabled first … causing
existing subscriber streams to terminate. Callers must re-subscribe"), but the observe
IPC command exposes it to independent callers who cannot coordinate a re-subscribe.
Observation is effectively per webview window over one shared cached wrapper, so a second
window calling Database.load(key).observe(...) on a key a first window already observes
tears down the first window's broker — the first window's subscribe callback silently
stops firing, with no error to either window.

Repro

Minimal, runnable repro (cargo run, prints an explicit verdict; the subscriber created
after the re-observe still receives its event, proving the write published and the probe is
sound):
https://github.com/yokuze/mcve/tree/23aa4a2acc7e0956ba499751770d4c54b9451da1/cases/004-sqlx-sqlite-toolkit-reobserve-kills-existing-subscribers

Root cause (rev e1b3836)

  • enable_observation drops the current observer before installing the new one (doc comment states existing streams terminate): wrapper.rs#L390-L402
  • ObservationBroker owns the sole change_tx: broadcast::Sender: broker.rs#L52-L58
  • observe command calls remove_for_db + enable_observation, exposing the teardown to independent callers: src/commands.rs#L573-L617

Expected

Re-observing should not silently disconnect existing subscribers — e.g. make
observe/enable_observation idempotent when the requested table set and config are
unchanged (keep the existing broker), support additive/reference-counted observers, or at
minimum deliver a distinguishable close reason so a caller can tell "someone re-observed"
apart from a normal shutdown.

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