I am streaming HTML 5 video with Express using fs.createReadStream(path).pipe(res);
which eventually causes the error Error: EMFILE: too many open files
if I refresh the page too many times (in the thousands). I assume I need to perform some kind of cleanup and close the file to prevent this but am unsure what needs to be done.
I am creating a read stream every time the user seeks to a part of the video which the client has not loaded which makes this problem happen in a matter of minutes. Task manager shows the same file open hundreds of times so it appears to never get closed.
Relevant part of the stream function:
fs.stat(path, function(err, stats) {
var size = stats.size;
var range = req.headers.range;
if (range) {
var parts = range.replace(/bytes=/, '').split('-');
var start = parseInt(parts[0]);
var end = parts[1] ? parseInt(parts[1]) : size - 1;
var chunksize = (end - start) + 1;
res.writeHead(206, {
'Content-Range': 'bytes ' + start + '-' + end + '/' + size,
'Accept-Ranges': 'bytes',
'Content-Length': chunksize,
'Content-Type': 'video/mp4'
});
fs.createReadStream(path, {start: start, end: end}).pipe(res);
} else {
res.writeHead(200, {
'Content-Length': size,
'Accept-Ranges': 'bytes',
'Content-Type': 'video/mp4'
});
fs.createReadStream(path).pipe(res);
}
});
On Linux/Unix
EMFILE
issues are resolved byulimit
. I'm not sure on windows. GoogleWindows ulimit EMFILE
gets to this Stack Overflowhttps://stackoverflow.com/a/729204/683017
Its saying 2048 file descriptors per process is limit on Windows. This would fit with what your saying
If this 2048 is a firm limit, and I'm not sure it is, (you'll have to google around to find out more about your specific OS).
Maybe think about rebalancing the load out to more processes, or more servers if possible.
It turns out the stream only gets destroyed and the file closed when the end is reached - which rarely happens as you would have to load the entire file without seeking or closing the browser.
To fix this you have to listen for the close event of the response and destroy the stream:
Sometimes the close handler is never called, even when it is placed on the first line in the request function. A fairly hacky way I found to fix this is to check if the socket is destroyed before creating the stream:
The fixed stream function: