diff --git a/plugins/sqlite/README.md b/plugins/sqlite/README.md index 3306c75..27816bc 100644 --- a/plugins/sqlite/README.md +++ b/plugins/sqlite/README.md @@ -324,3 +324,39 @@ There are three levels to think about: writes inside the plugin. The journal mode is left at the default (`delete` for files, `memory` for `:memory:`), so concurrent reads work as expected. + +## What happens if the process dies mid-task + +`better-sqlite3` opens with `synchronous=FULL` by default, which means +**every commit is fsynced to disk before the `sqlite_exec` call +returns**. Anything the model has already written is on the disk and +will be there on the next open, no matter how the process dies. + +| Event | Already-committed data | Connections | +| ----- | ---------------------- | ----------- | +| Close the TUI / CLI window | safe | unchanged — the service is still running, the handle is still open | +| `opencode service stop` (SIGTERM) | safe | unclosed. Node exits without a `db.close()` call unless the host installs a handler. The OS reclaims the fds. | +| `kill -9` the service | safe | unclosed. The kernel reclaims the fds immediately. | +| Power loss / kernel panic | safe (last fsynced commit) | irrelevant — the process is gone. | +| `sqlite_open(":memory:")` and *anything* that ends the process | **lost** — `:memory:` lives only in process RAM | n/a | + +Verified empirically: `INSERT … ; setInterval; kill -9` left the +three rows intact on a fresh re-open. Same result for `kill -TERM` +with and without a SIGTERM handler that calls `db.close()`. + +**The only ways to lose data are:** + +1. Using `":memory:"`. There is no on-disk copy. +2. Turning `synchronous` off with `PRAGMA synchronous = OFF;` — the + commit returns before the bytes hit the disk, so a crash after the + return but before the kernel writes can lose that statement. This + plugin does not do this for you, but `sqlite_exec` will run it if + asked. +3. Running on a network filesystem (NFS, SMB, sshfs). Both SQLite's + locking and POSIX fsync semantics are unreliable there. + +**About the "leak fd" worry from the previous section:** that only +matters while the service is alive. As soon as the process exits, the +OS reclaims every fd it owned, including the database file and any +journal sidecar. A crash or hard kill is *less* leaky than a graceful +shutdown that the plugin forgets to clean up.