I am using node + redis and I facing strange issue when ever I run my app , connect event of redis client is called multiple times automatically as written in redis.js file.
Below is my code Server.js:
var express=require('express');
var app=express();
var port=8000;
var path = require('path');
var logger=require('morgan');
var bodyParser = require('body-parser');
var router = express.Router();
app.use(logger('dev'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.get('/',function(req,res){
res.send({message:"Welcome to nodejs APIS"});
});
var redisObj=require('./redis.js');
app.use('/redischeck',redisObj);
app.listen(port,function(err,res){ if(err){ console.log("Server error");}else{console.log("Server running on port 8000");}});
redis.js
var express = require('express');
var router = express.Router();
var redis = require("redis");
var client = redis.createClient();
client.on('connect', function() {
console.log('connected'); // Prints multiple time in console
});
router.get('/', function(req, res) {
client.on("error", function (err) { console.log("Error " + err);});
client.set("foo", "bar", function (err, reply) {
client.quit();
res.json({status:'Success'});
});
});
module.exports=router;
I also cross checked this issue using 'netstat -na | grep 6379'.My observation were many connection were created and then went in to TIME_WAIT state which was strange because I just ran my app on my localhost without anyone connecting it from some other end.
Am I doing something wrong in code.
It was a mistake from my side I had changed timeout values in redis.conf file located at /etc/redis/redis.conf so that redis connection does not go in TIME_WAIT state for 60 sec.
Related
I have an existing project written in Express, where I've made a messaging system. Everything was working on POST/GET methods (to send and receive the messages).
I wanted to make them appear in real time, so I installed socket.io both on the client and server side. In my server.js I added these lines:
const http = require("http");
const io = require("socket.io");
const server = http.createServer();
const socket = io.listen(server);
and changed my app.listen(...) into server.listen(...).
Added also:
socket.on("connection", socket => {
console.log("New client connected");
socket.on('test', (test) => {
console.log('test-test')
});
socket.emit('hello', {hello:'hello!'});
socket.on("disconnect", () => console.log("Client disconnected"));
});
On the front part I put such code in the componentDidMount method:
const socket = socketIOClient();
socket.emit('test', {test:'test!'})
socket.on('hello', () => {
console.log('aaa')
})
Now I got 2 problems. Although the console.log() works correctly, I get an error on the React app:
WebSocket connection to 'ws://localhost:3000/sockjs-node/039/lmrt05dl/websocket' failed: WebSocket is closed before the connection is established.
Is that normal?
Also, when I change app.listen(...) into server.listen(...) in the server.js file, my routing stops working. All the POST and GET methods don't work, because the server is responding endlessly. Is that possible to use the socket.io just on a specific method in a specific routing file?
I keep my routes that way: app.use('/api/user', user); where user is a router file.
UPDATE:
full server.js require:
const express = require('express');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const bodyparser = require('body-parser');
const passport = require('passport');
const user = require('./routes/api/v1/User');
const company = require('./routes/api/v1/Company');
const http = require("http");
const io = require("socket.io");
const app = express();
dotenv.config();
app.use(passport.initialize());
require('./config/seed');
require('./config/passport')(passport);
const server = http.createServer();
const socket = io.listen(server);
You're not initializing server properly. Try making the following change
// const server = http.createServer();
const server = http.createServer(app);
and make sure you listen on server and not io
server.listen(PORT_GOES_HERE)
[UPDATE]
Working Example:
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
server.listen(80);
// WARNING: app.listen(80) will NOT work here!
// DO STUFF WITH EXPRESS SERVER
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
For more details check this: https://socket.io/docs/
I am learning Mongo DB, Mongoose and Node JS and I can't seem to connect my Node JS to local Mongo DB.
Here is my code:
dbtest.js
var express = require('express');
var app = express(); // create our app w/ express
var mongoose = require('mongoose'); // mongoose for mongodb
var morgan = require('morgan'); // log requests to the console (express4)
var bodyParser = require('body-parser'); // pull information from HTML POST (express4)
var methodOverride = require('method-override'); // simulate DELETE and PUT (express4)
var options = {
useMongoClient: true,
autoIndex: false, // Don't build indexes
reconnectTries: Number.MAX_VALUE, // Never stop trying to reconnect
reconnectInterval: 500, // Reconnect every 500ms
poolSize: 10, // Maintain up to 10 socket connections
// If not connected, return errors immediately rather than waiting for reconnect
bufferMaxEntries: 0
};
var Todo = mongoose.model('Todo', {
text : String
}, 'test');
var status = {
"status": "not connected"
};
app.get('/api/todos', function(req, res) {
mongoose.connect('mongodb://127.0.0.1:27017/exampleDB',options,function(err)
{
if (err) {
res.json(status);
} else {
res.json('Connected');
}
});
});
app.listen(8080);
console.log("App listening on port 8080");
When I call api/todos GET request, the status JSON object is returned, meaning I cannot connect to the database.
I installed MongoDB Enterprise Server 3.14.10 completely and have it running but I don't know why my NodeJS application cannot connect.
Any suggestions are appreciated.
Your first mongoose.connect() argument lacks username / password combination:
mongoose.connect('mongodb://username:password#127.0.0.1:27017/exampleDB');
Try to connect db first before doing any action. Once it connected try to use inside your custom function. Below code will helps you to test local database
const express = require('express');
const app = express();
const port = 3000;
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/dbname', { useMongoClient: true });
mongoose.connection.on('connected', () => {
console.log('Connected to database ');
});
mongoose.connection.on('error', (err) => {
console.log('Database error: '+err);
});
// Start Server
app.listen(port, () => {
console.log('Server started on port '+port);
});
Check your cmd window to see console.
For connecting to a local mongodb, you can use this URI, replacing USER, PASSWORD are DB with your values :
mongodb://USER:PASSWORD#127.0.0.1/DB?authSource=admin
You don't need to provide the port 27017, because it's the default one for mongodb.
The trick here is to add with 'authSource=admin' for enabling the authentication.
Documentation :
https://docs.mongodb.com/manual/reference/connection-string/#examples
I'm using Express4 with a router that points to path /, and that is handled by a JS file named chat.js.
And my IO object is already bind to app.io, so inside my chat.js I'll call my Socket.IO by using req.app.io, but the problem is, I use to be using socket.emit and the code just work fine, but now if I want to sync up with the client I have to using req.app.io.emit.
And since because I'm using req.app.io.emit, I have the connection keep increasing problem.
index.js
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const path = require('path');
const randomstring = require('randomstring');
const sha256 = require('sha256');
const io = require('socket.io').listen(server);
app.io = io;
const port = process.env.PORT || 3000;
module.exports.users = {};
server.listen(port, () => {
console.log(`Serer is running on port ${port}`);
});
app.set('view engine', 'ejs');
app.set('views', path.join(`${__dirname}/../public`));
app.use('/static', express.static(path.join(`${__dirname}/../public`)));
app.use('/', require('./chat'));
chat.js
const express = require('express');
const router = express.Router();
const users = require('./index').users;
const randomstring = require('randomstring');
router.get('/', (req, res) => {
res.render('index');
const uid = randomstring.generate(30);
users[uid] = true;
req.app.io.on('connection', socket => {
console.log('hello');
socket.on('disconnect', () => {
console.log('bye');
});
});
});
module.exports = router;
Log(Image)
Serer is running on port 3000
hello
bye
hello
hello
bye
bye
Every time your / route is hit, you create a new duplicate io.on('connection', ...) event handler. So, after that route is hit 3 times, you have 3 event handlers for the connection event. So, when it occurs, your code gets called 3 times.
Instead, you should do the io.on('connection', ...) only once outside the route.
FYI, you don't seem to be doing anything useful with the uid you are creating because you don't associate it with any particular connection. FYI, each socket.io connection already has a unique socket.id which is uniquely associated with each socket.io connection so that you can get the id from the socket or can retrieve the socket given only the id.
I'm trying to modularize my application files and I'm having problems with Socket.io. I would like to use the io inside my routes.js. Something like this:
var router = require('express').Router();
var io = require('./sockets/my-io');
router.get('/', function(req, res) {
io.emit('request-detected');
});
module.exports = router;
But I can't do, because the socket.io needs the app server, and when I'm inside the routes.js file, the app server is not listening or being exported yet.
Can you give me a solution, or any other approach to this problem?
Here's what I have, and if it's possible, I would like to keep the file structure:
app.js
var app = require('express')();
var routes = require('./routes');
/* ... */
app.use('/contacts', routes);
module.exports = app;
bin/www
#!/usr/bin/env node
var app = require('../wallet');
var server = app.listen(port, function() {
debug('Express is listening o port ' + port);
});
routes.js
var router = require('express').Router();
router.get('/', function(req, res) {
console.log('hey');
});
module.exports = router;
You can do it by passing the io variable to your routes module.
bin/www
#!/usr/bin/env node
var app = require('./app');
var server = app.listen(3000, function() {
console.log('Express is listening on port 3000');
}); // start the server
var socket = require('./socket')(server); // require socket.io code
var routes = require('./routes')(socket); // require routes
app.use('/', routes);
app.js
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.set('views engine', 'ejs');
app.set('views', __dirname + '/');
module.exports = app;
socket.js
var socketio = require('socket.io');
function init(server) {
var io = socketio(server);
io.on('connection', function (socket) {
console.log("socket connected");
socket.on('newEvent', function (data) {
console.log(data);
});
});
return io;
}
module.exports = init;
routes.js
var express = require('express');
var route = express.Router();
function init(io) {
route.get('/', function (req, res) {
res.render('index.ejs', {});
setTimeout(function() {io.emit('newEvent', {message: "Hi from the server"})}, 2000);
});
return route;
}
module.exports = init;
The code above worked for me. However, I'm not sure why you want to do that.
Inside the router, you still have full control of what you want to send to the user via html, so you can just add the data to the html directly.
The idea of socket.io is that you can send data between the client and back once he has loaded the html and established a connection to your server with socket.io.
As you can see in the routes.js, I had to add a timeout to the emit. This is because the socket event will be emit before the browser has reloaded the page. In my case the browser logged the event and then immediately refreshed, losing the data you just sent.
Another problem is that you don't know anything about the socket of the client that is requesting the page because he hasn't connected yet. This means that calling io.emit() will send the event to all connected sockets.
As I said, this really depends on what exactly you want to do.
EDIT:
Instead of updating your contacts using ajax, you can do that with socket.io.
socket.js
var socketio = require('socket.io');
function init(server) {
var io = socketio(server);
io.on('connection', function (socket) {
console.log("socket connected");
socket.on('newContact', function (data, callback) {
// add data.contactName to db
// after adding something, you use the callback to
// send the added data back to the client
// callback(newContact);
});
});
return io;
}
module.exports = init;
index.html
<script type="text/javascript" >
var socket = io();
// call this emit when the user wants to add a contact
socket.emit('newContact', {contactName: name}, function(newContact) {
// here you will get the result from the server and you can
// update the html with jquery for example
});
</script>
If i understand your question correctly ,maybe you can try this way.
in your routes.js file
var app = require('./app');
var server = require('http').createServer(app);
var io = require('./sockets/my-io')(server);
var route = app.Router();
in your app.js file
var port = process.env.PORT || 3000;
app.listen(port,function(){
console.log('server on port ' + port)
})
I am wondering if someone could help me point out how to cache a resource in express/node on startup of the web server. The myCol.find is very expensive, so I would like to just run it once on startup, and cache the result for all subsequent requests. Is there a startup step I can tie into? Can this be done synchronously before the server starts accepting requests?
I have the code below, but would like to reference a cached variable instead of the mongo db
var express = require('express');
var app = express();
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/test');
var myCol = require('./customModule');
var port = process.env.PORT || 8080;
var router = express.Router();
router.get('/test/:testId', function(req, res) {
myCol.find(function(err, allResults) {
res.json(allResults);
});
});
app.use('/api', router);
app.listen(port);
Yep, you just need to make sure your server starts listening after you've fetched your results through myCol.find():
var express = require('express');
var app = express();
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/test');
var myCol = require('./customModule');
var port = process.env.PORT || 8080;
var router = express.Router();
var myResultsCache;
router.get('/test/:testId', function(req, res) {
res.send(myResultsCache);
});
app.use('/api', router);
myCol.find(function(err, allResults) {
//you should add some error handling here
myResultsCache = allResults;
app.listen(port);
});
You could swap the order of myCol.find and the route handler, so that the relevant code would be:
myCol.find(function(error, results) {
if (error) throw error;
router.get('/test/:testId', function (request, response) {
response.json(results);
});
});
This is still asynchronous, but the server would only be able to respond after the find operation has been done.