From f6117c2c47cadf582c283dd970369a83b5485674 Mon Sep 17 00:00:00 2001 From: Nora Date: Mon, 12 Aug 2019 18:34:04 -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 e55652c5..47f102ff 100644 --- a/lib/datasource.js +++ b/lib/datasource.js @@ -187,6 +187,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 @@ -200,6 +205,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); }; @@ -2594,6 +2603,27 @@ DataSource.prototype.ping = function(cb) { return cb.promise; }; +/** + * 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 c7dd8ddb..ad864a25 100644 --- a/test/datasource.test.js +++ b/test/datasource.test.js @@ -352,4 +352,26 @@ describe('DataSource', function() { .should.not.containEql('TestModel'); }); }); + + 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'); + }); + }); });