I uses the following code to take advantage of cluster npm for my node app.
form = require("connect-form");
express = require("express");
app = express.createServer(form({ keepExtensions: true }));
cluster = require("cluster");
// App configuration
// ....
// Run on cluster
cluster( app )
.use(cluster.logger('logs'))
.use(cluster.stats())
.use(cluster.pidfiles('pids'))
.use(cluster.cli())
.listen(port);
This was working fine on node 0.4.4 but I end up with the following error on node 0.6.5
luc#localhost:~/server$ node app.js
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
TypeError: Property 'cluster' of object #<Object> is not a function
at Object.<anonymous> (/home/luc/server/app.js:15:1)
at Module._compile (module.js:432:26)
at Object..js (module.js:450:10)
at Module.load (module.js:351:31)
at Function._load (module.js:310:12)
at Array.0 (module.js:470:10)
at EventEmitter._tickCallback (node.js:192:40)
I know 'cluster' has been tested on 0.4.x node version but the error seems strange though.
Any idea ?
#mengxy nicely pointed to the documentation, but I was running into this same problem. I thought it would be good to point out a few things:
The example given in the LearnBoost cluster git repo (http://github.com/LearnBoost/cluster/blob/master/examples/express.js) does not work with Node 0.6 as of this writing.
As a recent adopter of Node, I'm at the mercy of many examples; I suspect others are as well. I haven't yet seen a good example of Node 0.6 + cluster + express (probably because Node 0.6 is still fairly recent).
So, derived from the nonworking example and the Node 0.6 docs #mengxy pointed to, here's an example of cluster serving an express app:
#!/usr/bin/env node
var cluster = require('cluster');
var express = require('express');
var os = require('os');
var app = express.createServer();
app.get('/', function(req, res){
res.send('Hello World from worker ' + process.env.NODE_WORKER_ID);
});
if (cluster.isMaster) {
// Fork workers. Two per core sounds reasonable to me.
for (var i = 0; i < os.cpus().length * 2; i++) {
var worker = cluster.fork();
}
} else {
// Worker processes have a http server.
app.listen(3000);
}
Cluster npm module has been integrated into node core in node 0.6, and there are some API changes.
You can find the API documents at http://nodejs.org/docs/v0.6.5/api/cluster.html#cluster
From Node.js on multi-core machines:
Node.JS v0.6.X includes the "cluster" module straight out of the box, which makes it easy to set up multiple node workers that can listen on a single port.
This is NOT the same as the learnboost "cluster" module.
http://nodejs.org/docs/latest/api/cluster.html
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.Server(function(req, res) { ... }).listen(8000);
}
Related
The assignment is about embedded system. We are learning how to use BeagleBone Black and how we can use it to make small-size devices e.g., devices that can measure temperature and pulse.
A part of our first assignment is to follow this guide: https://randomnerdtutorials.com/programming-the-beaglebone-black-with-bonescript/
We need to make a server in Node JS and a index in html. The site provides button to control a LED light that is connected to a breadboard via BeagleBone Black.
I have connected the LED, pins and wires to the BeagleBone Black. Installed Ubuntu 18.14, NodeJS, npm socket.io and Bonescript(Script dedicated to BeagleBone).
I am not using Cloud 9 IDE to run the server.js and index.html.
But I use terminal in Ubuntu.
To start the server i use this command: node server.js
I tried for several days to make the server and index.html to run,
but I get this error or nothing happends:
/home/ubuntu/bonescript/server.js:42
var io = require('socket.io').listen(server);
^
[TypeError: require(...).listen is not a function
at Object.<anonymous> (/home/ubuntu/bonescript/server.js:42:31)
at Module._compile (internal/modules/cjs/loader.js:1137:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
at Module.load (internal/modules/cjs/loader.js:985:32)
at Function.Module._load (internal/modules/cjs/loader.js:878:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
at internal/main/run_main_module.js:17:47
Can anyone help me pinpoint the problem? I am really stuck on this stage. Thanks.
index.html code:
<!DOCTYPE html>
<html>
<head>
<title>Home Automation Web Server with BeagleBone</title>
<script src = "/socket.io/socket.io.js" ></script>
<script>
// Establishing connection with server
var socket = io.connect();
// Changes the led state
function changeState(state){
if (state==1){
// Emit message changing the state to 1
socket.emit('changeState', '{"state":1}');
// Change led status on web page to ON
document.getElementById("outputStatus").innerHTML = "Status: ON";
}
else if (state==0){
// Emit message changing the state to 0
socket.emit('changeState', '{"state":0}');
// Change led status on web page to OFF
document.getElementById("outputStatus").innerHTML = "Status: OFF";
}
}
</script>
</head>
<h2>LED</h2>
<p id="outputStatus">Status</p>
<button type="button" onclick="changeState(1);">ON</button>
<button type="button" onclick="changeState(0);">OFF</button>
</div>
</body>
</html>
server.js code:
//Loading modules
var http = require('http');
var fs = require('fs');
var path = require('path');
var b = require('bonescript');
// Create a variable called led, which refers to P9_14
var led = "P9_14";
// Initialize the led as an OUTPUT
b.pinMode(led, b.OUTPUT);
// Initialize the server on port 8888
var server = http.createServer(function (req, res) {
// requesting files
var file = '.'+((req.url=='/')?'/index.html':req.url);
var fileExtension = path.extname(file);
var contentType = 'text/html';
// Uncoment if you want to add css to your web page
/*
if(fileExtension == '.css'){
contentType = 'text/css';
}*/
fs.exists(file, function(exists){
if(exists){
fs.readFile(file, function(error, content){
if(!error){
// Page found, write content
res.writeHead(200,{'content-type':contentType});
res.end(content);
}
})
}
else{
// Page not found
res.writeHead(404);
res.end('Page not found');
}
})
}).listen(8888);
// Loading socket io module
var io = require('socket.io').listen(server);
// When communication is established
io.on('connection', function (socket) {
socket.on('changeState', handleChangeState);
});
// Change led state when a button is pressed
function handleChangeState(data) {
var newData = JSON.parse(data);
console.log("LED = " + newData.state);
// turns the LED ON or OFF
b.digitalWrite(led, newData.state);
}
// Displaying a console message for user feedback
server.listen(console.log("Server Running ..."));
I have same problem but solve it already the code on this website is based on older node version, you have to change the code on line
var io = require('socket.io').listen(server);
to
var io = require('socket.io')(server);
and edit variable or remove this line since newer node cant use .listen function twice (the code already use it on server var to open port 8888)
server.listen(console.log("Server Running ..."));
socket.io is an internal library, not an external one. Therefore, when you ran npm install socket.io, you downloaded something that is not the socket.io that you want.
Delete your node_modules, and remove socket.io from package.json, and reinstall bonescript via npm install. Then it should work.
I have 2 servers with exactly the same setup. But on 1 server I ran against an error and on another server it works well.
On server 1 :
[root#tst socketio]# npm list socket.io
/var/socketio
└── socket.io#2.0.4
Package nodejs-0.10.48-3.el6.x86_64 already installed and latest version
On server 2 :
[root#1 socketio]# npm list socket.io
/var/socketio
└── socket.io#2.0.4
Package nodejs-0.10.48-3.el6.x86_64 already installed and latest version
Script on server 1 :
[root#tst socketio]# node /var/socketio/socketioclient.js 1768
Time: 5/3/2018 21:10:6
ID: 1768
Start connect
S-connection
k95RAgJVnhzv4ItHABvu
S-emit event
S-disconnect
Script on server 2 :
[root#1 socketio]# node /var/socketio/socketioclient.js 1768
Time: 5/3/2018 20:59:24
ID: 1768
/var/socketio/node_modules/socket.io-client/node_modules/engine.io-client/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js:66
var headers = Object.assign({}, defaultHeaders);
^
TypeError: Object function Object() { [native code] } has no method 'assign'
at new XMLHttpRequest (/var/socketio/node_modules/socket.io-client/node_modules/engine.io-client/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js:66:24)
at /var/socketio/node_modules/socket.io-client/node_modules/engine.io-client/lib/transports/polling.js:24:13
at Object.<anonymous> (/var/socketio/node_modules/socket.io-client/node_modules/engine.io-client/lib/transports/polling.js:26:3)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.require (module.js:364:17)
at require (module.js:380:17)
at Object.<anonymous> (/var/socketio/node_modules/socket.io-client/node_modules/engine.io-client/lib/transports/polling-xhr.js:6:15)
My socketioclient.js :
console.log(datetime);
console.log('ID: '+ID);
var io = require('socket.io-client');
console.log('Start connect');
var sSocket = io.connect('https://11.22.33.44:1234', {
reconnection: true,
reconnectionDelay: 1000,
reconnectionDelayMax : 5000,
reconnectionAttempts: 3
});
sSocket.on('connect', function (data) {
console.log('S-connection');
console.log(sSocket.id);
console.log('S-emit event');
sSocket.emit('event', { ID: ID });
sSocket.disconnect();
}
sSocket.on('serveroutput', function (data) {
console.log('S-serveroutput: '+data);
});
});
sSocket.on('disconnect', function (data) {
console.log('S-disconnect');
});
sSocket.on('reconnect', function() {
console.log('S-reconnecting');
});
sSocket.on('reconnect_failed', function (data) {
console.log('S-reconnect failed');
});
I see no difference in socketio version or in nodejs version. But the outcome is different. How come ?
I have read (on this website) about needing node version >= 4. But as it works on 1 server I don't think this is the issue here.
tl;dr Upgrade to the most recent Node LTS release (currently 8)
It looks like you have different versions of xmlhttprequest-ssl, even though the parent socket.io is at 2.0.4. xmlhttprequest-ssl version 1.5.4 or newer includes the use of Object.assign. Versions from 1.5.2 down might work better in Node 0.10.
If you look at the paths in the stack trace, there are a number of modules other than socket.io involved in the error:
socket.io-client/node_modules/engine.io-client/node_modules/xmlhttprequest-ssl
The npm command supported on Node 0.10 is non deterministic which means you can end up with two installs of the same parent module but they are made up from different child dependencies. This largely depends on when you ran the npm install as to what versions you get.
Recent versions of npm (5.x) and the yarn package manager now support lock files that fully describe an applications dependencies and will be able to create consistent installs over time.
A lot of modules have started dropping support for any Node versions prior to 4.x so this type of error is going to become more and more common for Node 0.x users.
Use the current Long Term Support release of Node. If you require packages for your RHEL platform, Nodesource provide rpms.
Until recently I started my node server like such
node server/server.js
where server.js was a simple expresss server
var app = express();
app.listen(PORT...
Now I am using cluster.js to start my application
var cluster = require('cluster');
if (cluster.isMaster) {
// Count the machine's CPUs
var cpuCount = require('os').cpus().length;
// Create a worker for each CPU
for (var i = 0; i < cpuCount; i += 1) {
cluster.fork();
}
// Listen for dying workers
cluster.on('exit', function () {
cluster.fork();
});
} else {
require('./server');
}
When i start my server using
node server/cluster.js
It works fine. Cluster.js starts server.js which then starts my express server.. so far so good.
However when I attempt o use forever with cluster.js .. something goes amiss. it does start the cluster.js file..however the below command does not work
forever stop server/cluster.js
I do need the above command to work because I am using flightplan for deployment and it needs to stop and start forever before each deployment.
Any suggestions on how I can make this happen ?
Here is a simplified version of my cluster Express app:
/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.
Questions:
var app = require('../'); will not work in this cluster environment. Which of the worker apps should it return? Should it return the cluster object instead of an Express app?
Now, obviously setting the port in the test script will not work. How would you set a port within a test script to a cluster of apps?
How would you send requests to this cluster of apps?
The only solution I can think of is to conditionally turn off the clustering feature and run only one app if the app is requested from a test script (if (module.parent.parent) ...).
Any other way to test a clustered Express app with Mocha?
It's been quite a long time since I have posted this question. Since no one has answered, I will answer to this question myself.
I kept the /index.js as it is:
module.exports = process.env.CODE_COV
? require('./lib-cov/app')
: require('./lib/app');
In /lib/app.js which starts the cluster, I have the following code. In brief, I start the cluster only in non-test environment. In test environment the cluster is not started but only one app/worker itself is started as defined in the cluster.isMaster && !module.parent.parent condition.
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);
}
}
In the above case !module.parent.parent will be evaluated as a truthful object only if the application was not started by a test script.
module is the current /lib/app.js script.
module.parent is its parent /index.js script.
module.parent.parent is undefined if the application was started directly via node index.js.
module.parent.parent is the test script if the application was started via one of the scripts.
Thus, I can safely start the script where I can set a custom port.
/test/test1.js
var app = require('../');
app.listen(7777);
// send requests to app, then assert the response.
At the same time if I need to run the application in real, i.e. not for testing, then I run node index.js and it will start up the cluster of applications.
I have a much simpler way of doing this
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();
}
Just make sure to set the env to test when running the tests
ex: NODE_ENV=test grunt test
I kind of liked your solution because of it's simplicity, however, in an environment like an MVC framework for node, you may end up chaining module.parent up to 11 times (seriously).
I think a better approach would be to simply check which script node started processing with. The node's command-line arguments are available at process.argv.
The first item in this array would be 'node', the executable and the second argument would be the path to the file that node start executing. This would be index.js in your case.
So instead of checking
module.parent.parent
^ ^
(app.js) |
(index.js)
You could do something like this
var starter = process.argv[1].split(path.sep).pop();
Where starter would be index or index.js depending on what you started your server with.
node index.js vs node index
The check would then look like:
if (cluster.isMaster && starter === 'index.js') {
cluster.fork();
}
Worked in my environments—I hope this helps!
I using cloud9 ide coding new project. When I deploy on cloudfoundry from cloud9ide. I have error
Application failed to start. Please note that CloudFoundry uses a different port to listen to. When calling 'listen()' use it like '.listen(process.env.PORT || process.env.VCAP_APP_PORT)'.
This is my source
var port = (process.env.VMC_APP_PORT || 3000);
var host = (process.env.VCAP_APP_HOST || 'localhost');
var http = require('http');
var env = process.env.VCAP_SERVICES ? JSON.parse(process.env.VCAP_SERVICES) : null;
var mongodata = env['mongodb-1.8'][0]['credentials'];
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n' + env);
}).listen(port, host);
This source have error when I get mongo object
var mongodata = env['mongodb-1.8'][0]['credentials'];
But not have this line deploy successful
Please help me !!
Thanks so much
As the error in the cloud9 console probably tells you (as it tells me when i try this :-) ):
haalasdoallalsakdl (CloudFoundry): [5/6] Crash log
============/logs/stderr.log============
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
TypeError: Cannot read property '0' of undefined
at Object.<anonymous> (/var/vcap/data/dea/apps/haalasdoallalsakdl-0-8be0d413a9ec29a79f665d388ce414bd/app/server.js:7:35)
at Module._compile (module.js:432:26)
at Object..js (module.js:450:10)
at Module.load (module.js:351:31)
at Function._load (module.js:310:12)
at Array.0 (module.js:470:10)
So there is no entry in VCAP_SERVICES called like that. When I console.log the process.env variable, there isn't even any service listed.
So you'll have to install the mongodb service for your app. Fastest to do this is via the CF VMC tools (can't run this in cloud9 at the moment, so you'll have to install this locally):
vmc create-service mongodb --bind your_app_name
Then it'll start up fine.
N.B. You can probably fix this in the .yml file, but I don't know how to do this :-)