From bca631518be7a45f000669f6e1b2a2f6bd4a1ad2 Mon Sep 17 00:00:00 2001 From: Dominique Emond Date: Thu, 1 Aug 2019 16:54:44 -0400 Subject: [PATCH] fix: prevent max listeners warning If establishing a database connection is slow and database migration runs and there are many models, sql operations are queued up and this leads to the node.js max emitters exceeded warning. A default value for max emitters has now been introduced, and it can also be configured in datasources.json. Co-authored-by: Dominique Emond --- lib/datasource.js | 30 ++++++++++++++++++++++++++++++ test/datasource.test.js | 22 ++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/lib/datasource.js b/lib/datasource.js index 6b6fe32e..f7530118 100644 --- a/lib/datasource.js +++ b/lib/datasource.js @@ -194,6 +194,11 @@ util.inherits(DataSource, EventEmitter); // allow child classes to supply a data access object DataSource.DataAccessObject = DataAccessObject; +/** + * Global maximum number of event listeners + */ +DataSource.DEFAULT_MAX_OFFLINE_REQUESTS = 16; + /** * Set up the connector instance for backward compatibility with JugglingDB schema/adapter * @private @@ -207,6 +212,10 @@ DataSource.prototype._setupConnector = function() { this.connector.dataSource = this; } const dataSource = this; + + // Set max listeners to a default/configured value + dataSource.setMaxListeners(dataSource.getMaxOfflineRequests()); + this.connector.log = function(query, start) { dataSource.log(query, start); }; @@ -2699,6 +2708,27 @@ DataSource.prototype.beginTransaction = function(options) { return Transaction.begin(this.connector, options); }; +/** + * Get the maximum number of event listeners + */ +DataSource.prototype.getMaxOfflineRequests = function() { + // Set max listeners to a default value + // Override this default value with a datasource setting + // 'maxOfflineRequests' from an application's datasources.json + + let maxOfflineRequests = DataSource.DEFAULT_MAX_OFFLINE_REQUESTS; + if ( + this.settings && + this.settings.maxOfflineRequests + ) { + if (typeof this.settings.maxOfflineRequests !== 'number') + throw new Error('maxOfflineRequests must be a number'); + + maxOfflineRequests = this.settings.maxOfflineRequests; + } + return maxOfflineRequests; +}; + /*! The hidden property call is too expensive so it is not used that much */ /** diff --git a/test/datasource.test.js b/test/datasource.test.js index a3795cd6..3e4427e4 100644 --- a/test/datasource.test.js +++ b/test/datasource.test.js @@ -545,6 +545,28 @@ describe('DataSource', function() { ds.connector.should.equal(connector); }); }); + + describe('getMaxOfflineRequests', () => { + let ds; + beforeEach(() => ds = new DataSource('ds', {connector: 'memory'})); + + it('sets the default maximum number of event listeners to 16', () => { + ds.getMaxOfflineRequests().should.be.eql(16); + }); + + it('uses provided number of listeners', () => { + ds.settings.maxOfflineRequests = 17; + ds.getMaxOfflineRequests().should.be.eql(17); + }); + + it('throws an error if a non-number is provided for the max number of listeners', () => { + ds.settings.maxOfflineRequests = '17'; + + (function() { + return ds.getMaxOfflineRequests(); + }).should.throw('maxOfflineRequests must be a number'); + }); + }); }); function givenMockConnector(props) {