Skip to content

Explicitly close realms on shutdown.#5933

Open
michelinewu wants to merge 2 commits into
masterfrom
mw_realm_shutdown
Open

Explicitly close realms on shutdown.#5933
michelinewu wants to merge 2 commits into
masterfrom
mw_realm_shutdown

Conversation

@michelinewu

@michelinewu michelinewu commented May 21, 2026

Copy link
Copy Markdown
Contributor

Close Realm Databases on Shutdown

Issues

RealmService opens two Realm databases at startup via connect():

  • persistentDb — file-backed LMDB database (persistent.realm, schema version 3)
  • ephemeralDb — in-memory Realm (ephemeral.realm)

The class had no close(), shutdown(), or destroy() method. Neither database was ever explicitly closed. The shutdown sequence in AppService made no attempt to close either instance.

Realm uses LMDB (Lightning Memory-Mapped Database) internally. LMDB maps database files into the process's virtual address space via mmap on macOS and a memory-mapped section object on Windows. LMDB is crash-safe by design and the copy-on-write structure means the data file itself is not corrupted by an unclean close. The risk is the stale reader entry on next startup and the possibility of a discarded in-flight write transaction.

Fixes

Added close() to RealmService and called this.realmService.close() in AppService.shutdownHandler() after obs.IPC.disconnect() and before crashReporterService.endShutdown(), making it the last local resource released before the shutdown complete signal is sent.

Files changed: app/services/realm.ts, app/services/app/app.ts

Implications of Not Fixing

Stale reader lock entry. LMDB maintains a reader lock table in a separate .lock file. Each open Realm connection registers an entry in this table keyed by PID. When the process exits without calling Realm.close(), the entry is not removed. On the next startup, LMDB must scan the reader table for dead PIDs and clean up stale entries before the environment can be opened. This adds latency to every app launch following an unclean exit and is a known source of MDB_READERS_FULL errors in environments with many restart cycles.

In-flight write transaction discarded. Realm.close() commits or rolls back any open write transaction before releasing the environment. If the process exits without closing, any write that was in-progress at the moment of shutdown is silently discarded. Whether this is a real risk depends on whether any write is ever left open across an async boundary where the shutdown IPC could arrive but the behavior on unclean exit is silent data loss with no error.

Page flush not guaranteed. Realm.close() calls mdb_env_close() internally, which flushes dirty pages from the OS page cache to disk via msync/FlushViewOfFile. Without this call, dirty pages are left to the OS to flush at its discretion. On a system under memory pressure, this increases the window during which committed data that has not yet reached physical storage is at risk.

Performance Implications

Metric Before After
Realm close on shutdown Not called — OS releases mmap on process exit Called synchronously; ~1–5ms per database
Next startup: stale reader cleanup LMDB scans lock table for dead PIDs after unclean exit Lock entry released cleanly; no scan needed
Disk flush guarantee Deferred to OS (seconds to minutes under memory pressure) msync/FlushViewOfFile called by LMDB close
In-flight write transaction Silently discarded on unclean exit Committed or rolled back cleanly

@bundlemon

bundlemon Bot commented May 21, 2026

Copy link
Copy Markdown

BundleMon

Files updated (1)
Status Path Size Limits
renderer.(hash).js
7.77MB (+467B +0.01%) -
Unchanged files (3)
Status Path Size Limits
vendors~renderer.(hash).js
4.67MB -
updater.js
115.29KB -
guest-api.js
40.23KB -

Total files change +467B 0%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

Comment thread app/services/app/app.ts
obs.NodeObs.RemoveVolmeterCallback();
obs.NodeObs.OBS_service_removeCallback();
obs.IPC.disconnect();
this.realmService.close();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only closes the worker window's Realm instance. To fully fix the stale-reader/unclean-close risk described in the PR, shutdown needs to close Realm in every renderer that opened it, or move the connection so only the worker opens it.

@michelinewu michelinewu marked this pull request as ready for review June 3, 2026 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants