sqlite: document what survives a process kill
User asked what happens if the window is closed mid-task. Added a 'What happens if the process dies mid-task' section that tabulates the four exit paths (TUI close, SIGTERM, SIGKILL, power loss) and empirically confirms that anything past the last fsync'd commit is on disk. The only ways to lose data are :memory:, an explicit synchronous=OFF, or a network filesystem. Also corrects the earlier 'leak fd' framing — a dead process leaks no fds, the OS reclaims them.
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user