RDB: fs.writeFile + fs.rename
JSON.stringify + writeFile + rename. The save is async; BGSAVE returns immediately and the event loop keeps serving. No fork, no worker_threads needed for small to medium stores.
Atomic snapshot via tmp file plus rename
async function rdbSave() {
const tmp = RDB_PATH + ".tmp";
const payload = {
version: 1, saved_at: Math.floor(Date.now() / 1000),
store: Object.fromEntries(STORE),
expires: Object.fromEntries(EXPIRES),
};
await writeFile(tmp, JSON.stringify(payload));
await rename(tmp, RDB_PATH);
lastSave = payload.saved_at;
}rdbSave is async. fs.rename is atomic. lastSave tracks success.
Worth knowing: real Redis takes its snapshot by calling fork(). The child process gets a copy-on-write view of memory and writes the file while the parent keeps serving clients. We skip that trick on purpose. By the time your script runs, Node has already spawned libuv helper threads, and fork() carries only the calling thread into the child. The other threads vanish mid-flight, which can leave internal locks held forever and deadlock the child. So in Node, BGSAVE is just an async function on the event loop.
Quiz: Quiz
Loading practice…