diff --git a/lib/control-connection.js b/lib/control-connection.js index 54b3e617..710036c5 100644 --- a/lib/control-connection.js +++ b/lib/control-connection.js @@ -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; @@ -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); } @@ -997,6 +1000,7 @@ class ControlConnection extends events.EventEmitter { // Cancel timers clearTimeout(this._topologyChangeTimeout); clearTimeout(this._nodeStatusChangeTimeout); + clearTimeout(this._reconnectTimeout); } /** diff --git a/test/integration/short/control-connection-tests.js b/test/integration/short/control-connection-tests.js index b4810216..5e514c04 100644 --- a/test/integration/short/control-connection-tests.js +++ b/test/integration/short/control-connection-tests.js @@ -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'); @@ -195,7 +196,7 @@ describe('ControlConnection', function () { 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); + const cc = newInstance(options, 1); disposeAfter(cc); await cc.init(); @@ -236,6 +237,30 @@ 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); + disposeAfter(cc); + + await cc.init(); + + // 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); + + // 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); + }); }); });