Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 5 additions & 1 deletion lib/control-connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ class ControlConnection extends events.EventEmitter {
this._topologyChangeTimeout = null;
// Timeout used for delayed handling of node status changes
this._nodeStatusChangeTimeout = null;
// Timeout used for scheduling reconnect
this._reconnectTimeout = null;

if (context && context.borrowHostConnection) {
this._borrowHostConnection = context.borrowHostConnection;
Expand Down Expand Up @@ -475,7 +477,8 @@ class ControlConnection extends events.EventEmitter {
if (!this._isShuttingDown) {
const delay = this._reconnectionSchedule.next().value;
this.log('warning', `ControlConnection could not reconnect, scheduling reconnection in ${delay}ms`);
setTimeout(() => this._refresh(), delay);
clearTimeout(this._reconnectTimeout);
this._reconnectTimeout = setTimeout(() => this._refresh(), delay);
this.emit('newConnection', err);
}

Expand Down Expand Up @@ -997,6 +1000,7 @@ class ControlConnection extends events.EventEmitter {
// Cancel timers
clearTimeout(this._topologyChangeTimeout);
clearTimeout(this._nodeStatusChangeTimeout);
clearTimeout(this._reconnectTimeout);
}

/**
Expand Down
49 changes: 49 additions & 0 deletions test/integration/short/control-connection-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
'use strict';
const assert = require('assert');
const util = require('util');
const sinon = require('sinon');

const helper = require('../../test-helper');
const Client = require('../../../lib/client.js');
Expand Down Expand Up @@ -236,6 +237,54 @@ describe('ControlConnection', function () {

assert.strictEqual(helper.lastOctetOf(cc.host), '2');
});

it('should stop reconnecting after control connection shutdown is called', async () => {
const options = clientOptions.extend(utils.extend({ pooling: { coreConnectionsPerHost: {}}}, helper.baseOptions));
const reconnectionDelay = 200;
options.policies.reconnection = new policies.reconnection.ConstantReconnectionPolicy(reconnectionDelay);
const cc = newInstance(options, 1, 1);
disposeAfter(cc);

await cc.init();

assert.ok(cc.host);
assert.strictEqual(helper.lastOctetOf(cc.host), '1');
const lbp = cc.options.policies.loadBalancing;

await new Promise(r => lbp.init({ log: utils.noop, options: { localDataCenter: 'dc1' }}, cc.hosts, r));

// the control connection host should be local or remote to trigger DOWN events
for (const h of cc.hosts.values()) {
h.setDistance(lbp.getDistance(h));
await h.warmupPool();
}

// stop nodes 1 and 2 and make sure they both go down.
await util.promisify(helper.ccmHelper.stopNode)(1);
await helper.wait.forNodeDown(cc.hosts, 1);
await util.promisify(helper.ccmHelper.stopNode)(2);
await helper.wait.forNodeDown(cc.hosts, 2);

// check that both hosts are down.
cc.hosts.forEach(h => {
if (helper.lastOctetOf(h) === '1') {
assert.strictEqual(h.isUp(), false);
}
else {
assert.strictEqual(h.isUp(), false);
}
});

// start spying on _refresh calls
cc._refresh = sinon.spy(cc._refresh);

cc.shutdown();

// wait for reconnectionDelay with 10% lag
await helper.delayAsync(parseInt(reconnectionDelay * 1.1, 10));

assert.ok(cc._refresh.notCalled);
});
});
});

Expand Down