Problem
events.db is opened by two independent Sembast handles that can be alive at the same time:
lib/core/app_bootstrap.dart:43 — foreground handle, created at bootstrap and never closed.
lib/background/background.dart:289 — background service isolate handle.
The background isolate writes through its handle:
background.dart:180 — persistChatEventFromBackground -> eventStore.putItem(id, record)
- called from
lib/features/notifications/services/background_notification_service.dart:273 (dispute chat) and :451 (peer chat)
Sembast IO keeps the store contents in memory per handle and does not re-read the file after open. Consequences:
- Stale reads. Any foreground read through
eventStorageProvider — dispute_chat_notifier.dart:222/313/447, chat_room_notifier.dart:167, session_notifier.dart:63, mostro_service.dart:109 — will not see records written by the background isolate until the app restarts and reopens the database.
- Dual-writer risk. Two writers appending to and compacting the same Sembast file is not a supported configuration and can lose records.
Today the user-visible impact is limited: the background service does not advance the chat cursors, so on resume the relay subscription refetches the missed events and the chat still fills in (see #675). The persisted records act as a dedup/marker layer, so the failure mode is a silent loss of that layer rather than missing messages — but it is fragile and will bite as soon as anything relies on the on-disk records being authoritative.
Suggested direction
Stop writing events.db from the background isolate. Options, roughly in order of preference:
- Have the background isolate send accepted-event records to the foreground over the
flutter_background_service channel and let the foreground (single owner of the handle) persist them. Requires a durable queue for the app-killed case.
- Keep an isolate-local write-ahead file in the background isolate and drain it into
events.db from the foreground on resume.
- Move to a storage engine that supports multi-isolate access.
Reopening the foreground database on resume is not a sufficient fix: eventDatabaseProvider is an overrideWithValue created at bootstrap, so every consumer would need rebuilding, and the dual-writer corruption risk would remain.
Context
Raised by an automated review on #675 (comment).
Problem
events.dbis opened by two independent Sembast handles that can be alive at the same time:lib/core/app_bootstrap.dart:43— foreground handle, created at bootstrap and never closed.lib/background/background.dart:289— background service isolate handle.The background isolate writes through its handle:
background.dart:180—persistChatEventFromBackground->eventStore.putItem(id, record)lib/features/notifications/services/background_notification_service.dart:273(dispute chat) and:451(peer chat)Sembast IO keeps the store contents in memory per handle and does not re-read the file after open. Consequences:
eventStorageProvider—dispute_chat_notifier.dart:222/313/447,chat_room_notifier.dart:167,session_notifier.dart:63,mostro_service.dart:109— will not see records written by the background isolate until the app restarts and reopens the database.Today the user-visible impact is limited: the background service does not advance the chat cursors, so on resume the relay subscription refetches the missed events and the chat still fills in (see #675). The persisted records act as a dedup/marker layer, so the failure mode is a silent loss of that layer rather than missing messages — but it is fragile and will bite as soon as anything relies on the on-disk records being authoritative.
Suggested direction
Stop writing
events.dbfrom the background isolate. Options, roughly in order of preference:flutter_background_servicechannel and let the foreground (single owner of the handle) persist them. Requires a durable queue for the app-killed case.events.dbfrom the foreground on resume.Reopening the foreground database on resume is not a sufficient fix:
eventDatabaseProvideris anoverrideWithValuecreated at bootstrap, so every consumer would need rebuilding, and the dual-writer corruption risk would remain.Context
Raised by an automated review on #675 (comment).