Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 10 additions & 18 deletions lib/connection.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,23 @@
"use strict";

var EventEmitter = require('events').EventEmitter
, spawn = require('child_process').spawn
, net = require('net')
, Utils = require('./utils')
, util = require('util');

exports.IssueLog = IssueLog; // connection issue handling
exports.Available = ping; // connection availablity

function ping (host, callback) {
var isWin = process.platform.indexOf('win') === 0; // win32 or win64
var arg = isWin ? '-n' : '-c';
var pong = spawn('ping', [arg, '3', host]); // only ping 3 times

pong.on('error', function onerror (error) {
callback(error, false);
pong.kill();
function ping (host, port, timeout, callback) {
var socket = net.createConnection({ port: port, host: host }, function (err) {
callback(err);
socket.end();
});

pong.stdout.on('data', function stdoutdata (data) {
callback(false, data.toString().split('\n')[0].substr(14));
pong.kill();
});
socket.setTimeout(timeout);

pong.stderr.on('data', function stderrdata (data) {
callback(new Error(data.toString().split('\n')[0].substr(14)), false);
pong.kill();
socket.on('error', function (err) {
callback(err);
socket.end();
});
}

Expand Down Expand Up @@ -115,7 +107,7 @@ issues.attemptReconnect = function attemptReconnect () {
this.emit('reconnecting', this.details);

// Ping the server
ping(this.tokens[1], function pingpong (err) {
ping(this.tokens[1], this.tokens[0] || 11211, this.config.maxTimeout || 100, function pingpong (err) {
// still no access to the server
if (err) {
issue.messages.push(err.message || 'No message specified');
Expand Down
61 changes: 40 additions & 21 deletions test/memcached-connections.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

var assert = require('assert')
, fs = require('fs')
, net = require('net')
, common = require('./common')
, Memcached = require('../');

Expand Down Expand Up @@ -122,7 +123,9 @@ describe('Memcached connections', function () {
minTimeout: 0,
maxTimeout: 100,
failures: 0,
reconnect: 100 })
// Reconnect timeout of 300ms is tied to 400ms test timeout,
// so only one reconnection attempt could occur
reconnect: 300 })
, reconnectAttempts = 0;

memcached.on('reconnecting', function() {
Expand All @@ -145,7 +148,7 @@ describe('Memcached connections', function () {
});
});
it('should reset failures after reconnecting to failed server', function(done) {
var server = '127.0.0.1:1234'
var server = '127.0.0.1:12340'
, memcached = new Memcached(server, {
retries: 0,
minTimeout: 0,
Expand All @@ -155,32 +158,48 @@ describe('Memcached connections', function () {
reconnect: 100 })

this.timeout(60000);

// First request will mark server failed
memcached.get('idontcare', function(err) {
assert.throws(function() { throw err }, /connect ECONNREFUSED/);
// Wait 10ms, server should be back online
setTimeout(function() {
// Second request will mark server dead
memcached.get('idontcare', function(err) {
assert.throws(function() { throw err }, /connect ECONNREFUSED/);
// Third request should find no servers

// Setting server up
var fakeServer = net.createServer();
fakeServer.listen(12340, '127.0.0.1', function() {
// Wait 10ms, server should be back online
setTimeout(function() {
// Tearing server down
fakeServer.close(function () {
// Second request will mark server dead
memcached.get('idontcare', function(err) {
assert.throws(function() { throw err }, /not available/);
// Give enough time for server to reconnect
setTimeout(function() {
// Server should be reconnected, but expect ECONNREFUSED
memcached.get('idontcare', function(err) {
assert.throws(function() { throw err }, /connect ECONNREFUSED/);
assert.deepEqual(memcached.issues[server].failures,
memcached.issues[server].config.failures);
memcached.end();
done();
assert.throws(function() { throw err }, /connect ECONNREFUSED/);
// Third request should find no servers
memcached.get('idontcare', function(err) {
assert.throws(function() { throw err }, /not available/);

// Setting server up once again
fakeServer = net.createServer();
fakeServer.listen(12340, '127.0.0.1', function() {
// Give enough time for server to reconnect
setTimeout(function() {
// And tearing new server down too
fakeServer.close(function () {
// Server should be reconnected, but expect ECONNREFUSED
memcached.get('idontcare', function(err) {
assert.throws(function() { throw err }, /connect ECONNREFUSED/);

assert.deepEqual(memcached.issues[server].failures,
memcached.issues[server].config.failures);
memcached.end();
done();
});
});
}, 150);
});
}, 150);
});
});
});
},10);
},10);
});
});
});
it('should default to port 11211', function(done) {
Expand Down