7

这是我的集群 Express 应用程序的简化版本:

/index.js

module.exports = process.env.CODE_COV
    ? require('./lib-cov/app')
    : require('./lib/app');

/lib/app.js

var cluster = require('cluster'),
    express = require('express'),
    app = module.exports = express.createServer();

if (cluster.isMaster) {
    // Considering I have 4 cores.
    for (var i = 0; i < 4; ++i) {
        cluster.fork();
    }
} else {
    // do app configurations, then...

    // Don't listen to this port if the app is required from a test script.
    if (!module.parent.parent) {
        app.listen(8080);
    }
}

/test/test1.js

var app = require('../');

app.listen(7777);

// send requests to app, then assert the response.

问题:

  1. var app = require('../');在此集群环境中不起作用。它应该返回哪个工作应用程序?它应该返回集群对象而不是 Express 应用程序吗?
  2. 现在,显然在测试脚本中设置端口是行不通的。您如何将测试脚本中的端口设置为应用程序集群?
  3. 您将如何向此应用程序集群发送请求?

我能想到的唯一解决方案是有条件地关闭集群功能,如果应用程序是从测试脚本(if (module.parent.parent) ...)请求的,则只运行一个应用程序。

还有其他方法可以使用 Mocha 测试集群 Express 应用程序吗?

4

3 回答 3

10

自从我发布这个问题以来已经很长时间了。由于没有人回答,我将自己回答这个问题。

我保持/index.js原样:

module.exports = process.env.CODE_COV
    ? require('./lib-cov/app')
    : require('./lib/app');

在启动集群的/lib/app.js中,我有以下代码。简而言之,我只在非测试环境中启动集群。在测试环境中,集群没有启动,但只有一个应用程序/工作程序本身按照条件中的定义启动cluster.isMaster && !module.parent.parent

var cluster = require('cluster'),
    express = require('express'),
    app = module.exports = express.createServer();

if (cluster.isMaster && !module.parent.parent) {
    // Considering I have 4 cores.
    for (var i = 0; i < 4; ++i) {
        cluster.fork();
    }
} else {
    // do app configurations, then...

    // Don't listen to this port if the app is required from a test script.
    if (!module.parent.parent) {
        app.listen(8080);
    }
}

在上述情况下!module.parent.parent,仅当应用程序不是由测试脚本启动时才会被评估为真实对象。

  1. module是当前的/lib/app.js脚本。
  2. module.parent是它的父/index.js脚本。
  3. module.parent.parentundefined如果应用程序是直接通过node index.js.
  4. module.parent.parent如果应用程序是通过其中一个脚本启动的,则为测试脚本。

因此,我可以安全地启动可以设置自定义端口的脚本。

/test/test1.js

var app = require('../');

app.listen(7777);

// send requests to app, then assert the response.

同时,如果我需要实际运行应用程序,即不是为了测试,那么我运行node index.js它会启动应用程序集群。

于 2013-10-25T04:51:02.673 回答
2

我有一个更简单的方法来做到这一点

    if (process.env.NODE_ENV !== 'test') {
    if (cluster.isMaster) {
        var numCPUs = require('os').cpus().length;
        console.log('total cpu cores on this host: ', numCPUs);
        for (var i = 0; i < numCPUs; i++) {
            console.log('forking worker...');
            cluster.fork();
        }

        cluster.on('online', function(worker) {
            console.log('Worker ' + worker.process.pid + ' is online.');
        });
        cluster.on('exit', function(worker, code, signal) {
            console.log('worker ' + worker.process.pid + ' died.');
        });
    } else {
        console.log('Im a worker');
        // application code 
        setupServer()
    }
} else {
    // when running tests
    setupServer();
    }

只需确保test在运行测试时将环境设置为:NODE_ENV=test grunt test

于 2015-10-08T16:53:06.547 回答
0

我有点喜欢你的解决方案,因为它很简单,但是,在像节点的 MVC 框架这样的环境中,你最终可能会链接 module.parent 多达 11 次(严重)。

我认为更好的方法是简单地检查哪个脚本节点开始处理。节点的命令行参数在 process.argv 中可用。该数组中的第一项将是“节点”,可执行文件和第二个参数将是节点开始执行的文件的路径。在您的情况下,这将是 index.js。

所以而不是检查

                   module.parent.parent
                            ^       ^        
                         (app.js)   |
                                (index.js)

你可以做这样的事情

var starter = process.argv[1].split(path.sep).pop();

starter将在哪里indexindex.js取决于您启动服务器的方式。 node index.js对比node index

然后检查将如下所示:

if (cluster.isMaster && starter === 'index.js') {
    cluster.fork();
}

在我的环境中工作——我希望这会有所帮助!

于 2014-05-17T19:12:38.373 回答