3

I am working on a node.js application that accesses the file system. In my testing, I have noticed something very strange that google has not been able to answer for me.

My code works fine 95% of the time, however, on occasion, I get this error: "Error: ENOENT, open 'test.Q3rax'" where test.Q3rax is a randomly generate filename. That file should be writeable, and if I run my code again, with the filename hardcoded in, it works just fine.

Here is the code where it is failing:

npJSON.prototype._writeFile = function(newData) {
    if (!this.loaded)
        throw "ERROR: npJSON._writeFile() was called before any data was loaded.";
    var stringToWrite = JSON.stringify(newData);
    fs.writeFile(this.fileName,stringToWrite, function(err) {
        if (err)
            throw err;
    });
};

Edit: For clarification, this is how I am generating the random filenames:

var filename = 'test.' + getRandomText(5,6);

function getRandomText(numberOfCharactersLow, numberOfCharactersHigh) {
    var numbChar = getRandomInt(numberOfCharactersLow, numberOfCharactersHigh);
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
    var returnText = '';
    for (var i = 0; i < numbChar; i++) {
        returnText += possible.charAt(getRandomInt(0, 62));
    }
    return returnText;
}

function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}
Nathan
  • 409
  • 4
  • 15
  • Is it possible that `fileName` contains a slash (or backslash)? `ENOENT`, in this context, most likely means that the dir you're trying to write the file to doesn't exist. – Aaron Dufour Feb 18 '14 at 02:54
  • That was what I was initially hoping when I saw the error, but then I started outputting file names to ensure it wasn't, and the file names are all valid. I will update my post to include how I am generating the file names. – Nathan Feb 18 '14 at 02:57
  • Do you have more than one process accessing the same file? I had a similar issue when running unit tests and my issue was a race condition of my own doing: http://stackoverflow.com/questions/10368806/node-js-readfile-woes – Hector Correa Feb 18 '14 at 03:04
  • It is possible that was the case, I made an effort to avoid that, but I may have missed it at some point. I haven't had it happen in a while now, even when I loop it without delay to try and force the error. Which honestly is unfortunate because I would like to have solved it rather than have it vanish. – Nathan Feb 18 '14 at 03:49

2 Answers2

3

It's possible you're running into the fact that files in Node aren't written with O_SYNC when written asynchronously. Which means that you might be trying to access the file before the kernel has flushed it to disk. There's a little more reading here (under the header fs.writeFile()): http://www.daveeddy.com/2013/03/26/synchronous-file-io-in-nodejs/

EDIT: Here is an example to forcefully demonstrate the problem:

var fs = require('fs');
var fname = '/tmp/fs.' + process.pid + '.tmp';
var buf = new Buffer(1024);
buf.fill('a');

fs.writeFile(fname, buf, function(err) {
  console.log(err);
});

try {
  fs.readFileSync(fname);
} catch(e) {
  console.log(e.stack);
}

process.on('exit', function() {
  try { fs.unlinkSync(fname); } catch(e) {}
});

// Output:
// Error: ENOENT, no such file or directory '/tmp/fs.31281.tmp'
Trevor Norris
  • 20,499
  • 4
  • 26
  • 28
  • I'm going to have to chalk it up to this, I double checked and am confident there was only one stream accessing the file. Thank you for the insightful link – Nathan Feb 18 '14 at 22:23
0

My guess is that you have multiple streams accessing the file at the same time. I would take a look at locking:

https://github.com/71104/rwlock

Justin Beckwith
  • 7,686
  • 1
  • 33
  • 55