diff --git a/src/QueueConfig.js b/src/QueueConfig.js index 87f83df..1e9cd04 100644 --- a/src/QueueConfig.js +++ b/src/QueueConfig.js @@ -28,6 +28,8 @@ class QueueConfig { rpcQueueMaxSize = 100, logger = console, + shuffleUrls = false, + // Queue & exchange options rpcClientAssertReplyQueueOptions = {}, rpcClientExchangeOptions = {}, @@ -58,6 +60,8 @@ class QueueConfig { this.rpcQueueMaxSize = rpcQueueMaxSize this.logger = logger + this.shuffleUrls = shuffleUrls + // Queue & exchange options this.rpcClientAssertReplyQueueOptions = rpcClientAssertReplyQueueOptions this.rpcClientExchangeOptions = rpcClientExchangeOptions diff --git a/src/QueueConnection.js b/src/QueueConnection.js index f6410fe..bc6a08d 100644 --- a/src/QueueConnection.js +++ b/src/QueueConnection.js @@ -108,6 +108,10 @@ class QueueConnection extends EventEmitter { } async _connectWithMultipleUrls (urls, options) { + if (this._config.shuffleUrls) { + urls = this.shuffleUrls(urls) + } + for (const url of urls) { const connectionUrl = QueueConfig.urlStringToObject(url) try { @@ -122,6 +126,11 @@ class QueueConnection extends EventEmitter { throw new Error('RabbitMQ connection filed with multiple urls') } + shuffleUrls (urls) { + // shuffle urls - try to connect to nodes in a random order + return [...urls].sort((a, b) => 0.5 - Math.random()) + } + /** * @return Promise * */ diff --git a/test/QueueConnection.test.js b/test/QueueConnection.test.js index fc89a7f..c8755fb 100644 --- a/test/QueueConnection.test.js +++ b/test/QueueConnection.test.js @@ -95,6 +95,34 @@ describe('QueueConnection', () => { assert.deepEqual(connection._activeConnectionConfig, QueueConfig.urlStringToObject(config.url)) }) + it('#shuffleUrls() really shuffles the received urls and QueueConnection can still connect to the correct url', async () => { + const original = ['amqps://random-host:5671', config.url] + const connection = new QueueConnection(copyConfig({ + url: original, + shuffleUrls: true + })) + + let canDoTheSame = false + let canDoDifferent = false + + for (let i = 1; i <= 100 && !(canDoTheSame && canDoDifferent); i++) { + const shuffled = connection.shuffleUrls(original) + + if (JSON.stringify(original) === JSON.stringify(shuffled)) { + canDoTheSame = true + } else { + canDoDifferent = true + } + } + + // This test failing has a chance of 1 in 2^100 (==1,267,650,600,228,229,401,496,703,205,376) + assert.isTrue(canDoDifferent, 'connect urls shuffle failed to create different order out of a 100 tries') + assert.isTrue(canDoTheSame, 'connect urls shuffle failed to create same order out of a 100 tries') + + await connection.connect() + assert.isNotNull(connection._connection) + }) + it('#close() closes connection to RabbitMQ', async () => { const connection = new QueueConnection(config) try {