Skip to content

Commit 5a8fe13

Browse files
committed
avoid calling timed destroy too early before app instance created
1 parent 5455fa1 commit 5a8fe13

File tree

7 files changed

+84146
-41
lines changed

7 files changed

+84146
-41
lines changed

src/ember-app.js

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,13 @@ class EmberApp {
230230
return this.buildAppInstance()
231231
.then(instance => {
232232
result.instance = instance;
233+
result._startDestroyTimer();
233234
registerFastBootInfo(fastbootInfo, instance);
234235
return instance.boot(bootOptions);
235236
})
236237
.then(() => result.instanceBooted = true)
237238
.then(() => result.instance.visit(path, bootOptions))
238-
.then(() => fastbootInfo.deferredPromise)
239-
.then(() => result);
239+
.then(() => fastbootInfo.deferredPromise);
240240
}
241241

242242
/**
@@ -271,29 +271,13 @@ class EmberApp {
271271
let shouldRender = (options.shouldRender !== undefined) ? options.shouldRender : true;
272272
let bootOptions = buildBootOptions(shouldRender);
273273
let fastbootInfo = new FastBootInfo(
274-
req,
275-
res,
274+
req, res,
276275
{ hostWhitelist: this.hostWhitelist, metadata: options.metadata }
277276
);
278277

279278
let doc = bootOptions.document;
280279

281-
let result = new Result({
282-
doc: doc,
283-
html: html,
284-
fastbootInfo: fastbootInfo
285-
});
286-
287-
let destroyAppInstanceTimer;
288-
if (destroyAppInstanceInMs > 0) {
289-
// start a timer to destroy the appInstance forcefully in the given ms.
290-
// This is a failure mechanism so that node process doesn't get wedged if the `visit` never completes.
291-
destroyAppInstanceTimer = setTimeout(function() {
292-
if (result._destroyAppInstance()) {
293-
result.error = new Error('App instance was forcefully destroyed in ' + destroyAppInstanceInMs + 'ms');
294-
}
295-
}, destroyAppInstanceInMs);
296-
}
280+
let result = new Result({ doc, html, fastbootInfo, destroyAppInstanceInMs });
297281

298282
return this.visitRoute(path, fastbootInfo, bootOptions, result)
299283
.then(() => {
@@ -304,13 +288,7 @@ class EmberApp {
304288
})
305289
.catch(error => result.error = error)
306290
.then(() => result._finalize())
307-
.finally(() => {
308-
if (result._destroyAppInstance()) {
309-
if (destroyAppInstanceTimer) {
310-
clearTimeout(destroyAppInstanceTimer);
311-
}
312-
}
313-
});
291+
.finally(() => result._destroyAppInstance());
314292
}
315293

316294
/**

src/result.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class Result {
1515
this._doc = options.doc;
1616
this._html = options.html;
1717
this._fastbootInfo = options.fastbootInfo;
18+
this._destroyAppInstanceInMs = options.destroyAppInstanceInMs;
19+
this._destroyAppInstanceTimer = undefined;
1820
}
1921

2022
/**
@@ -97,10 +99,23 @@ class Result {
9799
}
98100
}
99101

102+
_startDestroyTimer() {
103+
if (this._destroyAppInstanceInMs > 0 && !this._instanceDestroyed) {
104+
// start a timer to destroy the appInstance forcefully in the given ms.
105+
// This is a failure mechanism so that node process doesn't get wedged if the `visit` never completes.
106+
this._destroyAppInstanceTimer = setTimeout(()=> {
107+
if (this._destroyAppInstance()) {
108+
this.error = new Error('App instance was forcefully destroyed in ' + this._destroyAppInstanceInMs + 'ms');
109+
}
110+
}, this._destroyAppInstanceInMs);
111+
}
112+
}
113+
100114
_destroyAppInstance() {
101115
if (this.instance && !this._instanceDestroyed) {
102116
this._instanceDestroyed = true;
103117
this.instance.destroy();
118+
clearTimeout(this._destroyAppInstanceTimer);
104119
return true;
105120
}
106121
return false;

test/fastboot-test.js

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -103,23 +103,12 @@ describe("FastBoot", function() {
103103

104104
it("can forcefully destroy the app instance using destroyAppInstanceInMs", function(done) {
105105
var fastboot = new FastBoot({
106-
distPath: fixture('basic-app')
106+
distPath: fixture('long-resolving-app')
107107
});
108108

109-
// delaying `visitRoute` to forcefully destroy app instance
110-
let originalVisitRoute = fastboot._app.visitRoute;
111-
fastboot._app.visitRoute = function() {
112-
return originalVisitRoute.apply(this, arguments)
113-
.then(function() {
114-
return new Promise(function(resolve) {
115-
setTimeout(resolve, 2000);
116-
});
117-
});
118-
};
119-
120-
fastboot.visit('/', { destroyAppInstanceInMs: 5 })
109+
fastboot.visit('/', { destroyAppInstanceInMs: 300 })
121110
.catch((e) => {
122-
expect(e.message).to.equal('App instance was forcefully destroyed in 5ms');
111+
expect(e.message).to.equal('App instance was forcefully destroyed in 300ms');
123112
done();
124113
});
125114
});

0 commit comments

Comments
 (0)