shama / gaze

:crystal_ball: A globbing fs.watch wrapper built from the best parts of other fine watch libs.
MIT License
1.16k stars 167 forks source link

RangeError: Maximum call stack size exceeded #126

Open zivester opened 10 years ago

zivester commented 10 years ago

This is the same error as on #94 , but I'm able to reproduce it on v0.10.28. Is this just a limitation on this lib? Why can others support watching more than ~5k files?

reproduce:

var fs = require('fs'),
    os = require('os'),
    gaze = require('gaze'),
    ext = '.tmp',
    files = 5000; // 4456 seems to be enough on my system

var dir = os.tmpdir() + '/gaze-tmp/';

!fs.existsSync(dir) && fs.mkdirSync(dir);

for (var i = 0; i < files; i++) {
    fs.writeFileSync(dir + i + ext, '');
}

gaze(dir + '*' + ext, function(err){
    if (err) return console.log(err);
    console.log('success!');
    process.exit(0);
});

output

zivester@forever:~$ node gaze.js 

/home/zivester/node_modules/gaze/lib/helper.js:114
          callback(null);
          ^
RangeError: Maximum call stack size exceeded

May be relevant (also happens on Ubuntu 14.04)

zivester@forever:~$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=12.04
DISTRIB_CODENAME=precise
DISTRIB_DESCRIPTION="Ubuntu 12.04.4 LTS"
zivester@forever:~$ uname -a
Linux forever 3.2.0-25-generic #40-Ubuntu SMP Wed May 23 20:30:51 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
zivester@forever:~$ ulimit -n
1024
zivester@forever:~$ ulimit -Hn
4096
zivester@forever:~$ ulimit -Sn
1024
zivester@forever:~$ sudo sysctl  -a | grep fs.inotify
fs.inotify.max_user_instances = 128
fs.inotify.max_user_watches = 8192
fs.inotify.max_queued_events = 16384
cmawhorter commented 8 years ago

this is an issue on node 0.12 / gaze v0.5.2 as well. i tracked the problem down to the forEachSeries iterator.

wrapping iterator in a nextTick resolves the issue. https://github.com/shama/gaze/blob/v0.5.2/lib/helper.js#L52

dropping this in after your gaze include fixed it for me:

var gazeHelper = require('gaze/lib/helper.js');
gazeHelper.forEachSeries = function forEachSeries(arr, iterator, callback) {
  if (!arr.length) { return callback(); }
  var completed = 0;
  var iterate = function() {
    process.nextTick(function() {
      iterator(arr[completed], function (err) {
        if (err) {
          callback(err);
          callback = function() {};
        } else {
          completed += 1;
          if (completed === arr.length) {
            callback(null);
          } else {
            iterate();
          }
        }
      });
    });
  };
  iterate();
};