I have simple example:
var redis = require('redis'),
client = redis.createClient();
var test = function() {
client.brpop('log', 0, function(err, reply) {
if (err != null ) {
console.log(err);
} else {
.... parse log string ....
}
test();
});
}
test();
How to reconnect redis connection after restart redis server ?
The Redis client automatically reconnects. Just make sure you handle the "error" event from the client. As per the example:
var redis = require('redis');
client = redis.createClient();
client.on('error', function(err){
console.error('Redis error:', err);
});
Otherwise, this code is where the process begins.
this.emit("error", new Error(message));
// "error" events get turned into exceptions if they aren't listened for. If the user handled this error
// then we should try to reconnect.
this.connection_gone("error");
Next, the .connection_gone() method runs on the client.
Notice that you can also listen to a "reconnecting" event to be notified when this happens.
Related
So I modified the accepted answer in this thread How do I shutdown a Node.js http(s) server immediately? and was able to close down my nodejs server.
// Create a new server on port 4000
var http = require('http');
var server = http.createServer(function (req, res) { res.end('Hello world!'); }).listen(4000);
// Maintain a hash of all connected sockets
var sockets = {}, nextSocketId = 0;
server.on('connection', function (socket) {
// Add a newly connected socket
var socketId = nextSocketId++;
sockets[socketId] = socket;
console.log('socket', socketId, 'opened');
// Remove the socket when it closes
socket.on('close', function () {
console.log('socket', socketId, 'closed');
delete sockets[socketId];
});
});
...
when (bw == 0) /*condition to trigger closing the server*/{
// Close the server
server.close(function () { console.log('Server closed!'); });
// Destroy all open sockets
for (var socketId in sockets) {
console.log('socket', socketId, 'destroyed');
sockets[socketId].destroy();
}
}
However, on the client side, the client throws a ConnectionException because of the server.close() statement. I want the client to throw a SocketTimeoutException, which means the server is active, but the socket just hangs. Someone else was able to do this with a jetty server from Java
Server jettyServer = new Server(4000);
...
when (bw == 0) {
server.getConnectors()[0].stop();
}
Is it possible to achieve something like that? I've been stuck on this for a while, any help is extremely appreciated. Thanks.
What you ask is impossible. A SocketTimeoutException is thrown when reading from a connection that hasn't terminated but hasn't delivered any data during the timeout period.
A connection closure does not cause it. It doesn't cause a ConnectionException either, as there is no such thing. It causes either an EOFException, a null return from readLine(), a -1 return from read(), or an IOException: connection reset if the close was abortive.
Your question doesn't make sense.
I want to know form a stand alone Node application if a remote server (running with Socket.io) is up and listening for incoming connections.
If the server is up and listening, then connect with socket-io.client, and if not, record something to a DB.
I don't know how to accomplish this with socket-io.client. The address has IP and Port, so I just can't ping to the IP without the port.
Any ideas? Thanks!
You can just attempt to make a socket.io connection to the server. If it succeeds, then it is listening. If it fails, then apparently it is not listening. Here's a way to do that:
// check a socket.io connection on another server from a node.js server
// can also by used from browser client by removing the require()
// pass hostname and port in URL form
// if no port, then default is 80 for http and 447 for https
// 2nd argument timeout is optional, defaults to 5 seconds
var io = require('socket.io-client');
function checkSocketIoConnect(url, timeout) {
return new Promise(function(resolve, reject) {
var errAlready = false;
timeout = timeout || 5000;
var socket = io(url, {reconnection: false, timeout: timeout});
// success
socket.on("connect", function() {
clearTimeout(timer);
resolve();
socket.close();
});
// set our own timeout in case the socket ends some other way than what we are listening for
var timer = setTimeout(function() {
timer = null;
error("local timeout");
}, timeout);
// common error handler
function error(data) {
if (timer) {
clearTimeout(timer);
timer = null;
}
if (!errAlready) {
errAlready = true;
reject(data);
socket.disconnect();
}
}
// errors
socket.on("connect_error", error);
socket.on("connect_timeout", error);
socket.on("error", error);
socket.on("disconnect", error);
});
}
checkSocketIoConnect("http://192.168.1.10:8080").then(function() {
// succeeded here
}, function(reason) {
// failed here
});
I want my application (lets say a simple node file for now) to work as it is even if redis is not available. I'm not able to do it the correct way. This is what I've tried.
var redis = require('redis');
var redisClient = null;
var getRedisClient = function(){
if(redisClient){
return redisClient;
}
try {
redisClient = redis.createClient({connect_timeout : 5000, max_attempts : 1});
redisClient.on("error", function(err) {
console.error("Error connecting to redis", err);
redisClient = null;
});
return redisClient;
} catch(ex){
console.log("error initialising redis client " + ex);
return null;
}
};
try {
var client = getRedisClient();
console.log("done!");
} catch (ex){
console.log("Exception");
}
However, with this code my application exits if redis is not available (it shouldn't because i've not given a process.exit() command).
How can I solve this?
Checking for Successful Connection on Start
Using a promise, you could guarantee that at least initially, you were able to connect to redis without error within a specified time period:
const redis = require('redis');
const Promise = require('bluebird');
function getRedisClient(timeoutMs){
return new Promise((resolve, reject) => {
const redisClient = redis.createClient();
const timer = setTimeout(() => reject('timeout'), timeoutMs);
redisClient.on("ready", () => {
clearTimeout(timer);
resolve(redisClient);
});
redisClient.on("error", (err) => {
clearTimeout(timer);
reject(err);
});
});
};
const redisReadyTimeoutMs = 10000;
getRedisClient(redisReadyTimeoutMs)
.then(redisClient => {
// the client has connected to redis sucessfully
return doSomethingUseful();
}, error => {
console.log("Unable to connect to redis", error);
});
You Need Proper Error Handling
The redis client being non-null does NOT guarantee using it won't throw an error.
you could experience infrastructure misfortune e.g. crashed redis process, out of memory or network being down.
a bug in your code could cause an error e.g. invalid or missing arguments to a redis command.
You should be handling redis client errors as a matter of course.
DON'T null the Redis Client on Error
It won't give you much but it will force you to check for null every time you try and use it.
The redis client also has inbuilt reconnect and retry mechanisms that you'll miss out on if you null it after the first error. See the redis package docs, look for retry_strategy.
DO Wrap your redis client code with try .. catch ... or use .catch in your promise chain.
DO Make use of a retry_strategy.
Currently I'm using https://github.com/mranney/node_redis as my node redis client.
client.retry_delay is set to 250ms default.
I tried connecting to redis and once connection was successful, I manually stopped the redis server to see whether client.retry_delay works. But I didn't see it working.
The following log messages are logged on ready & end events on redisClients created using createClient:
[2012-03-30 15:13:05.498] [INFO] Development - Node Application is running on port 8090
[2012-03-30 15:13:08.507] [INFO] Development - Connection Successfully Established to '127.0.0.1' '6379'
[2012-03-30 15:16:33.886] [FATAL] Development - Connection Terminated to '127.0.0.1' '6379'
I didn't see Success message again [ready event was not fired] when the server came back live.
Am I missing something? When will be the retry constant used? Is there a work around to find whether a redis server has come up after a failure from node?
I can't reproduce this. Could you try this code, stop your redis server, and check the log output?
var client = require('redis').createClient();
client.on('connect' , log('connect'));
client.on('ready' , log('ready'));
client.on('reconnecting', log('reconnecting'));
client.on('error' , log('error'));
client.on('end' , log('end'));
function log(type) {
return function() {
console.log(type, arguments);
}
}
Answer # Feb-2020
const redis = require('redis');
const log = (type, fn) => fn ? () => {
console.log(`connection ${type}`);
} : console.log(`connection ${type}`);
// Option 1: One connection is enough per application
const client = redis.createClient('6379', "localhost", {
retry_strategy: (options) => {
const {error, total_retry_time, attempt} = options;
if (error && error.code === "ECONNREFUSED") {
log(error.code); // take actions or throw exception
}
if (total_retry_time > 1000 * 15) { //in ms i.e. 15 sec
log('Retry time exhausted'); // take actions or throw exception
}
if (options.attempt > 10) {
log('10 attempts done'); // take actions or throw exception
}
console.log("Attempting connection");
// reconnect after
return Math.min(options.attempt * 100, 3000); //in ms
},
});
client.on('connect', log('connect', true));
client.on('ready', log('ready', true));
client.on('reconnecting', log('reconnecting', true));
client.on('error', log('error', true));
client.on('end', log('end', true));
For complete running example clone node-cheat and run node connect-retry.js.
Adding to the answer above. Small change. The callback provided should be a method name and not execute the method itself. Something like below:
function redisCallbackHandler(message){
console.log("Redis:"+ message);
}
var redis = require("redis");
var redisclient = redis.createClient();
redisclient.on('connect', redisCallbackHandler);
redisclient.on('ready', redisCallbackHandler);
redisclient.on('reconnecting', redisCallbackHandler);
redisclient.on('error', redisCallbackHandler);
redisclient.on('end', redisCallbackHandler);
I'm trying out node.js and socket.io. I wan't to use to remove a ping function I have to get updates from my server. Here is an example code of what I'm doing:
var app = require('http').createServer(),
io = require('socket.io').listen(app),
cp = require('child_process');
app.listen(8080);
//I check a global value for all the connected users from the php command line
var t = setInterval(function(){
cp.exec('/usr/bin/php /Users/crear/Projects/MandaFree/symfony api:getRemainingMessages',
function(err, stdout){
if (err) {
io.sockets.emit('error', 'An error ocurred while running child process.');
} else {
io.sockets.emit('change', stdout);
}
console.log('Remaining messages: ' + stdout);
});
}, 3000);
var remaining = io.of('/getRemainingMessages')
.on('connection', function(socket){
socket.on('disconnect', function(){});
});
The Issue here, is that when I call io.sockets.emit() the debug console tells me it is doing something, but it looks like it is not getting to the clients. Because they are doing nothing.
I use to have one interval for every connected client, and when I used socket.emit() it did worked. But it is not the optimal solution.
UPDATE:
Here is my client side code.
var remaining = io.connect('http://127.0.0.1:8080/getRemainingMessages');
remaining.on('change', function(data){
console.log('Remaining messages: ' + data );
$('#count').html(data);
});
remaining.on('error', function(error){
console.log(error);
});
Had a very similar issue couple of days back and looks like socket.io had some changes in the API. I have never worked with symfony and am hoping the issues are the same.
I have a working demo of socket.io sending and receiving a message - uploaded to https://github.com/parj/node-websocket-demo as a reference
Essentially two changes
On Server side - changed socket.on to socket.sockets.on
var socket = io.listen(server);
socket.sockets.on('connection', function(client)
On Client side - URL and port not required as it is autodetected.
var socket = io.connect();
This has been tested using Express 2.5.2 and Socket.io 0.8.7
I have amalgamated your server code with mine, would you be able to try this on the server and my client javascript and client html just to see if it is working?
var socket = io.listen(server);
socket.sockets.on('connection', function(client){
var connected = true;
client.on('message', function(m){
sys.log('Message received: '+m);
});
client.on('disconnect', function(){
connected = false;
});
var t = setInterval(function(){
if (!connected) {
return;
}
cp.exec('/usr/bin/php /Users/crear/Projects/MandaFree/symfony api:getRemainingMessages',
function(err, stdout){
if (err) {
client.send('error : An error ocurred while running child process.');
} else {
client.send('change : ' + stdout);
}
console.log('Remaining messages: ' + stdout);
});
}, 3000);
t();
});