-
-
Notifications
You must be signed in to change notification settings - Fork 34.2k
Description
Is your feature request related to a problem? Please describe.
Please describe the problem you are trying to solve.
i have a build-system (in debian-docker under windows) that async-updates files w/ multiple child_processes doing fs.writeFile, fs.unlink, fs.link.
there are occasional race-conditions (i can't discern how) where one child_process writing to a file while another child_process unlinking-and-hardlinking ends up with file unlinked.
Describe the solution you'd like
Please describe the desired behavior.
mkstemp would make file-writes "atomic" by writing to tmpfile and then "atomically" rename it to destination. this might resolve the race condition from my multiple child_processes and allow the final hardlink to succeed.
ideal solution of atomic file-write with mkstemp:
/*jslint browser, node*/
/*global os*/
function fsWriteFileWithMkdirpAtomic(pathname, data, onError) {
/*
* this file with async-atomically write <data> to <pathname> with auto mkdir -p
*/
let fs;
let path;
let throwOnError;
throwOnError = function (err) {
/*
* this function will throw <err> if exists
* we typically want program to crash on <err> in ci/build use-case
*/
if (err) {
throw err;
}
};
try {
fs = require("fs");
path = require("path");
// win32-compat
pathname = path.resolve(pathname);
} catch (ignore) {
// do nothing in browser-env
onError();
return;
}
fs.mkstemp(os.tmpdir(), function (err, tmpfile) {
throwOnError(err);
fs.writeFile(tmpfile, data, function (err) {
throwOnError(err);
// fs.rename attempt #1
fs.rename(tmpfile, pathname, function (err) {
if (!err) {
onError();
return;
}
// mkdir -p
fs.mkdirp(path.dirname(pathname), {
recursive: true
}, function (ignore) {
// fs.rename attempt #2
fs.rename(tmpfile, pathname, function (err) {
throwOnError(err);
onError();
});
});
});
});
});
}
fsWriteFileWithMkdirpAtomic("aa/bb/cc/dd/foo", "hello world", function () {
console.log("successfully wrote file atomically with no race-condition");
});Describe alternatives you've considered
Please describe alternative solutions or features you have considered.
- use a random generator to create tmpfile in os.tmpdir(), which is not idead for obvious reasons.
- or use
fs.mkdtempand deal with cleaninup tmpdir after atomic-write, which again, not ideal.