【问题标题】:phantomjs-node crashes when attempting to scale behind node-clusterphantomjs-node 尝试在 node-cluster 后面扩展时崩溃
【发布时间】:2015-05-29 01:19:26
【问题描述】:

相关的 GitHub 问题:https://github.com/sgentle/phantomjs-node/issues/280

我有一个简单的应用程序,它执行以下操作:

var
    phantom = require('phantom'),
    express = require('express'),
    serve = express();

serve.get('/foo', function (req, res) {
    try {
        phantom.create(function (ph) {
            console.log('Phantom browser created w/ pid: ', ph.process.pid);
            ph.onError = function (msg, trace) {
                var msgStack = ['PHANTOM ERROR: ' + msg];
                if (trace && trace.length) {
                    msgStack.push('TRACE:');
                    trace.forEach(function (t) {
                        msgStack.push(' -> ' + (t.file || t.sourceURL) + ': ' + t.line + (t.function ? ' (in function ' + t.function + ')' : ''));
                    });
                }
                console.log(msgStack.join('\n'));
            };
            ph.createPage(function(page){
                page.open('http://www.stackoverflow.com', function(status){
                    res.json({pageStatus: status});
                    page.close();
                    ph.exit();
                });
            });
        });
    } catch(e){
        console.log(e);
        throw e;
    }

});

只要我在 WebStorm 中运行它,它就可以正常运行,并且我可以使用任意数量的并发请求访问 /foo 端点,并且一切都按预期运行。

但是,只要我尝试使用pm2 start -i 0 phantomapp.js 将其扩展到 PM2 之后,只要我不向它发出太多请求,一切仍然可以正常工作。第二次我打开两个浏览器窗口并在两者中刷新,我在pm2 logs 中得到以下信息。此时,由 PM2 管理的所有 8 个进程都“消失”了!我究竟做错了什么?? :

PM2: 2015-05-27 18:53:17: [PM2] Error caught by domain:
PM2: AssertionError: false == true
PM2:     at RoundRobinHandle.add (cluster.js:140:3)
PM2:     at queryServer (cluster.js:480:12)
PM2:     at Worker.onmessage (cluster.js:438:7)
PM2:     at ChildProcess.<anonymous> (cluster.js:692:8)
PM2:     at ChildProcess.emit (events.js:129:20)
PM2:     at handleMessage (child_process.js:324:10)
PM2:     at Pipe.channel.onread (child_process.js:352:11)
PM2: 2015-05-27 18:53:18: [PM2] Automatic `pm2 update` failed. Killing PM2 daemon and its processes...
PM2: 2015-05-27 18:53:18: pm2 has been killed by signal, dumping process list before exit...
PM2: 2015-05-27 18:53:18: Stopping app:phantomapp id:0
PM2: assert.js:86
PM2:   throw new assert.AssertionError({
PM2:         ^
PM2: AssertionError: false == true
PM2:     at RoundRobinHandle.add (cluster.js:140:3)
PM2:     at queryServer (cluster.js:480:12)
PM2:     at Worker.onmessage (cluster.js:438:7)
PM2:     at ChildProcess.<anonymous> (cluster.js:692:8)
PM2:     at ChildProcess.emit (events.js:129:20)
PM2:     at handleMessage (child_process.js:324:10)
PM2:     at Pipe.channel.onread (child_process.js:352:11)
phantomapp-0 (err): Process disconnected from parent !
PM2: [PM2] Spawning PM2 daemon
PM2: 2015-05-27 18:53:18: [PM2][WORKER] Started with refreshing interval: 30000
PM2: 2015-05-27 18:53:18: [[[[ PM2/God daemon launched ]]]]
PM2: 2015-05-27 18:53:18: BUS system [READY] on port /Users/matthewmarcus/.pm2/pub.sock
PM2: 2015-05-27 18:53:18: RPC interface [READY] on port /Users/matthewmarcus/.pm2/rpc.sock
PM2: [PM2] PM2 Successfully daemonized
PM2: Be sure to have the latest version by doing `npm install pm2@latest -g` before doing this procedure.
PM2: [PM2] Stopping PM2...
PM2: [PM2][WARN] No process found
PM2: [PM2] All processes have been stopped and deleted
PM2: 2015-05-27 18:53:18: PM2 is being killed via kill method
PM2: 2015-05-27 18:53:18: RPC socket closed
PM2: 2015-05-27 18:53:18: PUB socket closed
PM2: [PM2] PM2 stopped
PM2: 2015-05-27 18:53:19: [PM2][WORKER] Started with refreshing interval: 30000
PM2: 2015-05-27 18:53:19: [[[[ PM2/God daemon launched ]]]]
PM2: 2015-05-27 18:53:19: BUS system [READY] on port /Users/matthewmarcus/.pm2/pub.sock
PM2: 2015-05-27 18:53:19: RPC interface [READY] on port /Users/matthewmarcus/.pm2/rpc.sock
PM2: >>>>>>>>>> PM2 updated
PM2: ┌──────────┬────┬──────┬─────┬────────┬─────────┬────────┬────────┬──────────┐
PM2: │ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
PM2: └──────────┴────┴──────┴─────┴────────┴─────────┴────────┴────────┴──────────┘
PM2:  Use `pm2 show <id|name>` to get more details about an app

您可以使用节点原生集群重现相同的问题:

var cluster = require('cluster');

if(cluster.isMaster){
    var cpuCount = require('os').cpus().length;

    for (var i = 0; i < cpuCount; i++){
        cluster.fork();
    }

    cluster.on('exit', function(worker){
        console.log('Worker ' + woker.id + ' died. Forking...');
        cluster.fork();
    });

} else {
    var
        phantom = require('phantom'),
        express = require('express'),
        serve = express();

    serve.get('/foo', function (req, res) {
        try {
            phantom.create(function (ph) {
                console.log('Phantom browser created w/ pid: ', ph.process.pid);
                ph.onError = function (msg, trace) {
                    var msgStack = ['PHANTOM ERROR: ' + msg];
                    if (trace && trace.length) {
                        msgStack.push('TRACE:');
                        trace.forEach(function (t) {
                            msgStack.push(' -> ' + (t.file || t.sourceURL) + ': ' + t.line + (t.function ? ' (in function ' + t.function + ')' : ''));
                        });
                    }
                    console.log(msgStack.join('\n'));
                };
                ph.createPage(function(page){
                    page.open('http://www.stackoverflow.com', function(status){
                        res.json({pageStatus: status});
                        page.close();
                        ph.exit();
                    });
                });
            });
        } catch(e){
            console.log(e);
            throw e;
        }

    });
}

当尝试同时处理 > 1 个请求时,会在控制台中产生以下错误:

assert.js:86
  throw new assert.AssertionError({
        ^
AssertionError: false == true
    at RoundRobinHandle.add (cluster.js:140:3)
    at queryServer (cluster.js:480:12)
    at Worker.onmessage (cluster.js:438:7)
    at ChildProcess.<anonymous> (cluster.js:692:8)
    at ChildProcess.emit (events.js:129:20)
    at handleMessage (child_process.js:324:10)
    at Pipe.channel.onread (child_process.js:352:11)

【问题讨论】:

    标签: javascript node.js multithreading phantomjs pm2


    【解决方案1】:

    我尝试使用this gist 并且能够创建幻像浏览器并获得响应。

    • 如果我在 localhost:3000/foo 上运行两个选项卡,则只有在第一个选项卡结束时才会生成第二个选项卡。
    • 如果我在我的浏览器 (chrome) 中运行两个以上的并发请求,我也会收到错误消息。
      • 如果我尝试运行的请求(来自 bash)多于集群的数量,则会崩溃。
    • 如果我从 bash 脚本运行请求(小于或等于集群数),它根本不会崩溃。

      另外,我注意到使用 bash 脚本我正在同时运行所有内容:

      http GET localhost:3000/foo &
      http GET localhost:3000/foo &
      http GET localhost:3000/foo &
      http GET localhost:3000/foo &
      

    您看到的错误来自this assertion

      assert(worker.id in this.all === false);
    

    意味着工人不再是循环赛。

    我认为这与 PM2 没有直接关系,但有一个错误。 PM2 不应崩溃。我通过引用此 stackoverflow 建议您的 report an issue。如果是节点错误,不确定是否可以修复。

    遗憾的是,目前没有解决此问题的方法,但您可以查看nodejs issue。我读过 iojs 解决了这个问题,也许你可以试一试;)。

    另一个相关的stackoverflow:NodeJS Cluster unexpected assert.AssertionError

    【讨论】:

    • 是的。我认为这根本不是 PM2 问题。我用一个更简单的示例更新了问题,该示例直接处理集群分叉,并且在那里引发了相同的错误。 “这意味着工人不再参加循环赛。”由于该断言在RoundRobinHandle.add 中,这不意味着相反吗?它试图添加的工人已经在 rr 中?我大约 100% 确定这是因为 phantomjs-node 如何使用节点的 child_process 与 phantomjs 进程进行通信。我将使用我为 phantomjs-node 创建的 github 问题更新答案
    • 对我来说,这似乎不是 phatomjs 错误,而是 nodejs 问题,请参阅我的最后 2 个链接。可以试试 iojs 吗?
    • 您引用的nodejs问题中的错误堆栈指向SharedHandle.add,而不是RoundRobinHandle.add,不确定这两种情况是否相同?
    • 我的错你当前的 nodejs/pm2 版本是什么?注意he 犯了同样的错误..
    • 是的.. 猜测可能是同一件事:github.com/joyent/node/blob/master/lib/cluster.js#L99 看起来在这两种情况下,它只是验证工人尚未被添加。但这听起来是正确的,对吧?你不会希望同一个工人被添加两次,所以这听起来像是 phantomjs-node 在这里使用了 ```spawn()`:github.com/sgentle/phantomjs-node/blob/master/phantom.js#L17 可能是罪魁祸首,而后者又使用了 require(child_process).spawn( ) (github.com/ForbesLindesay/win-spawn/blob/master/index.js#L1)
    猜你喜欢
    • 1970-01-01
    • 2018-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-23
    • 1970-01-01
    • 1970-01-01
    • 2015-04-22
    相关资源
    最近更新 更多