From 4ce75bb81cffc35164b420f9aadae3969e086365 Mon Sep 17 00:00:00 2001 From: Erik Erikson Date: Fri, 15 Nov 2019 12:45:02 -0800 Subject: [PATCH] only print a final promise tracking report if a progress report was previously printed This reduces the noise of this component. See discussion at https://github.com/serverless/serverless/pull/6960#issuecomment-554515331 --- lib/classes/PromiseTracker.js | 41 ++++++++++++--- lib/classes/PromiseTracker.test.js | 84 +++++++++++++++++++----------- 2 files changed, 89 insertions(+), 36 deletions(-) diff --git a/lib/classes/PromiseTracker.js b/lib/classes/PromiseTracker.js index 0abaa46bb..10b742cb5 100644 --- a/lib/classes/PromiseTracker.js +++ b/lib/classes/PromiseTracker.js @@ -2,6 +2,12 @@ const logInfo = require('./Error').logInfo; +const constants = { + pending: 'pending', + rejected: 'rejected', + resolved: 'resolved', +}; + class PromiseTracker { constructor() { this.reset(); @@ -10,6 +16,7 @@ class PromiseTracker { this.promiseList = []; this.promiseMap = {}; this.startTime = Date.now(); + this.reported = false; } start() { this.reset(); @@ -20,9 +27,9 @@ class PromiseTracker { const pending = this.getPending(); logInfo( [ - '##########################################################################################', + '############################################################################################', `# ${delta}: ${this.getSettled().length} of ${this.getAll().length} promises have settled`, - `# ${delta}: ${pending.length} unsettled promises:`, + `# ${delta}: ${pending.length} are taking longer than expected:`, ] .concat(pending.map(promise => `# ${delta}: ${promise.waitList}`)) .concat([ @@ -31,22 +38,36 @@ class PromiseTracker { ]) .join('\n ') ); + this.reported = true; } stop() { clearInterval(this.interval); + if (this.reported) { + logInfo( + [ + '############################################################################################', + `# Completed after ${Date.now() - this.startTime}ms`, + `# ${this.getAll().length} promises are in the following states:`, + `# ${constants.resolved}: ${this.getResolved().length}`, + `# ${constants.rejected}: ${this.getRejected().length}`, + `# ${constants.pending}: ${this.getPending().length}`, + '##########################################################################################', + ].join('\n ') + ); + } this.reset(); } add(variable, prms, specifier) { const promise = prms; promise.waitList = `${variable} waited on by: ${specifier}`; - promise.state = 'pending'; + promise.state = constants.pending; promise.then( // creates a promise with the following effects but that we otherwise ignore () => { - promise.state = 'resolved'; + promise.state = constants.resolved; }, () => { - promise.state = 'rejected'; + promise.state = constants.rejected; } ); this.promiseList.push(promise); @@ -62,10 +83,16 @@ class PromiseTracker { return promise; } getPending() { - return this.promiseList.filter(p => p.state === 'pending'); + return this.promiseList.filter(p => p.state === constants.pending); } getSettled() { - return this.promiseList.filter(p => p.state !== 'pending'); + return this.promiseList.filter(p => p.state !== constants.pending); + } + getResolved() { + return this.promiseList.filter(p => p.state === constants.resolved); + } + getRejected() { + return this.promiseList.filter(p => p.state === constants.rejected); } getAll() { return this.promiseList; diff --git a/lib/classes/PromiseTracker.test.js b/lib/classes/PromiseTracker.test.js index 5635a6a86..ff01b29b9 100644 --- a/lib/classes/PromiseTracker.test.js +++ b/lib/classes/PromiseTracker.test.js @@ -28,45 +28,71 @@ describe('PromiseTracker', () => { promiseTracker.report(); // shouldn't throw return Promise.all(promiseTracker.getAll()); }); - it('reports no pending promises when none have been added', () => { - const promises = promiseTracker.getPending(); - expect(promises).to.be.an.instanceof(Array); - expect(promises.length).to.equal(0); + it('reports no promises when none have been added', () => { + expect(promiseTracker.getAll()).to.be.an('array').that.is.empty; + expect(promiseTracker.getPending()).to.be.an('array').that.is.empty; + expect(promiseTracker.getSettled()).to.be.an('array').that.is.empty; + expect(promiseTracker.getResolved()).to.be.an('array').that.is.empty; + expect(promiseTracker.getRejected()).to.be.an('array').that.is.empty; }); - it('reports one pending promise when one has been added', () => { + it('reports the correct number of added promise statuses', () => { let resolve; - const promise = new BbPromise(rslv => { + const pending = new BbPromise(rslv => { resolve = rslv; }); - promiseTracker.add('foo', promise, '${foo:}'); + const resolved = BbPromise.resolve(); + const rejected = BbPromise.reject('reason'); + promiseTracker.add('pending', pending, '${pending:}'); + promiseTracker.add('resolved', resolved, '${resolved:}'); + promiseTracker.add('rejected', rejected, '${rejected:}'); + resolved.state = 'resolved'; + rejected.state = 'rejected'; return BbPromise.delay(1) .then(() => { - const promises = promiseTracker.getPending(); - expect(promises).to.be.an.instanceof(Array); - expect(promises.length).to.equal(1); - expect(promises[0]).to.equal(promise); + const pendings = promiseTracker.getPending(); + expect(pendings).to.be.an.instanceof(Array); + expect(pendings.length).to.equal(1); + expect(pendings[0]).to.equal(pending); + const settleds = promiseTracker.getSettled(); + expect(settleds).to.be.an.instanceof(Array); + expect(settleds.length).to.equal(2); + expect(settleds).to.include(resolved); + expect(settleds).to.include(rejected); + const resolveds = promiseTracker.getResolved(); + expect(resolveds).to.be.an.instanceof(Array); + expect(resolveds.length).to.equal(1); + expect(resolveds).to.include(resolved); + const rejecteds = promiseTracker.getRejected(); + expect(rejecteds).to.be.an.instanceof(Array); + expect(rejecteds.length).to.equal(1); + expect(rejecteds).to.include(rejected); }) .then(() => { resolve(); }); }); - it('reports no settled promises when none have been added', () => { - const promises = promiseTracker.getSettled(); - expect(promises).to.be.an.instanceof(Array); - expect(promises.length).to.equal(0); - }); - it('reports one settled promise when one has been added', () => { - const promise = BbPromise.resolve(); - promiseTracker.add('foo', promise, '${foo:}'); - promise.state = 'resolved'; - const promises = promiseTracker.getSettled(); - expect(promises).to.be.an.instanceof(Array); - expect(promises.length).to.equal(1); - expect(promises[0]).to.equal(promise); - return Promise.all(promiseTracker.getAll()); - }); - it('reports no promises when none have been added', () => { - const promises = promiseTracker.getAll(); - expect(promises).to.be.an('array').that.is.empty; + it('reports and then clears tracked promises when stopped after reporting.', () => { + let resolve; + const pending = new BbPromise(rslv => { + resolve = rslv; + }); + const resolved = BbPromise.resolve(); + const rejected = BbPromise.reject('reason'); + promiseTracker.add('pending', pending, '${pending:}'); + promiseTracker.add('resolved', resolved, '${resolved:}'); + promiseTracker.add('rejected', rejected, '${rejected:}'); + resolved.state = 'resolved'; + rejected.state = 'rejected'; + promiseTracker.reported = true; + return BbPromise.delay(1).then(() => { + const all = promiseTracker.getAll(); + expect(all).to.be.an.instanceof(Array); + expect(all.length).to.equal(3); + promiseTracker.stop(); + const stopped = promiseTracker.getAll(); + expect(stopped).to.be.an.instanceof(Array); + expect(stopped.length).to.equal(0); + resolve(); + }); }); });