@@ -11,15 +11,12 @@ const BaseContextClass = require('./utils/base_context_class');
1111const utils = require ( './utils' ) ;
1212const Router = require ( './utils/router' ) ;
1313const Timing = require ( './utils/timing' ) ;
14+ const Lifecycle = require ( './lifecycle' ) ;
1415
1516const DEPRECATE = Symbol ( 'EggCore#deprecate' ) ;
16- const CLOSESET = Symbol ( 'EggCore#closeSet' ) ;
17- const ISCLOSE = Symbol ( 'EggCore#isClose' ) ;
18- const CLOSE_PROMISE = Symbol ( 'EggCore#closePromise' ) ;
1917const ROUTER = Symbol ( 'EggCore#router' ) ;
2018const EGG_LOADER = Symbol . for ( 'egg#loader' ) ;
21- const INIT_READY = Symbol ( 'EggCore#initReady' ) ;
22-
19+ const CLOSE_PROMISE = Symbol ( 'EggCore#closePromise' ) ;
2320
2421class EggCore extends KoaApplication {
2522
@@ -44,16 +41,9 @@ class EggCore extends KoaApplication {
4441
4542 this . timing = new Timing ( ) ;
4643
47- // register a close set
48- this [ CLOSESET ] = new Set ( ) ;
4944 // cache deprecate object by file
5045 this [ DEPRECATE ] = new Map ( ) ;
5146
52- this [ INIT_READY ] ( ) ;
53-
54- this . timing . start ( 'Application Start' ) ;
55- this . ready ( ( ) => this . timing . end ( 'Application Start' ) ) ;
56-
5747 /**
5848 * @member {Object} EggCore#options
5949 * @private
@@ -108,6 +98,15 @@ class EggCore extends KoaApplication {
10898 */
10999 this . Service = Service ;
110100
101+ this . lifecycle = new Lifecycle ( {
102+ baseDir : options . baseDir ,
103+ app : this ,
104+ logger : this . console ,
105+ } ) ;
106+ this . lifecycle . on ( 'error' , err => this . emit ( 'error' , err ) ) ;
107+ this . lifecycle . on ( 'ready_timeout' , id => this . emit ( 'ready_timeout' , id ) ) ;
108+ this . lifecycle . on ( 'ready_stat' , data => this . emit ( 'ready_stat' , data ) ) ;
109+
111110 /**
112111 * The loader instance, the default class is {@link EggLoader}.
113112 * If you want define
@@ -207,111 +206,71 @@ class EggCore extends KoaApplication {
207206 * @param {Function|GeneratorFunction|AsyncFunction } scope function will execute before app start
208207 */
209208 beforeStart ( scope ) {
210- if ( ! is . function ( scope ) ) {
211- throw new Error ( 'beforeStart only support function' ) ;
212- }
213-
214- // get filename from stack
215- const name = utils . getCalleeFromStack ( true ) ;
216- const timingkey = 'Before Start in ' + utils . getResolvedFilename ( name , this . options . baseDir ) ;
217-
218- this . timing . start ( timingkey ) ;
219-
220- const done = this . readyCallback ( name ) ;
209+ this . lifecycle . registerBeforeStart ( scope ) ;
210+ }
221211
222- // ensure scope executes after load completed
223- process . nextTick ( ( ) => {
224- utils . callFn ( scope ) . then ( ( ) => {
225- done ( ) ;
226- this . timing . end ( timingkey ) ;
227- } , err => {
228- done ( err ) ;
229- this . timing . end ( timingkey ) ;
230- } ) ;
231- } ) ;
212+ /**
213+ * register an callback function that will be invoked when application is ready.
214+ * @see https://github.com/node-modules/ready
215+ * @since 1.0.0
216+ * @param {boolean|Error|Function } flagOrFunction -
217+ * @return {Promise|null } return promise when argument is undefined
218+ * @example
219+ * const app = new Application(...);
220+ * app.ready(err => {
221+ * if (err) throw err;
222+ * console.log('done');
223+ * });
224+ */
225+ ready ( flagOrFunction ) {
226+ return this . lifecycle . ready ( flagOrFunction ) ;
232227 }
233228
234229 /**
235- * Close all, it will close
236- * - callbacks registered by beforeClose
237- * - emit `close` event
238- * - remove add listeners
230+ * If a client starts asynchronously, you can register `readyCallback`,
231+ * then the application will wait for the callback to ready
239232 *
240- * If error is thrown when it's closing, the promise will reject.
241- * It will also reject after following call.
242- * @return { Promise } promise
233+ * It will log when the callback is not invoked after 10s
234+ *
235+ * Recommend to use { @link EggCore#beforeStart}
243236 * @since 1.0.0
237+ *
238+ * @param {String } name - readyCallback task name
239+ * @param {object } opts -
240+ * - {Number} [timeout=10000] - emit `ready_timeout` when it doesn't finish but reach the timeout
241+ * - {Boolean} [isWeakDep=false] - whether it's a weak dependency
242+ * @return {Function } - a callback
243+ * @example
244+ * const done = app.readyCallback('mysql');
245+ * mysql.ready(done);
244246 */
245- close ( ) {
246- if ( this [ CLOSE_PROMISE ] ) return this [ CLOSE_PROMISE ] ;
247-
248- const closeFunction = async ( ) => {
249- // close in reverse order: first created, last closed
250- const closeFns = Array . from ( this [ CLOSESET ] ) ;
251- for ( const fn of closeFns . reverse ( ) ) {
252- await utils . callFn ( fn ) ;
253- this [ CLOSESET ] . delete ( fn ) ;
254- }
255- // Be called after other close callbacks
256- this . emit ( 'close' ) ;
257- this . removeAllListeners ( ) ;
258- this [ ISCLOSE ] = true ;
259- } ;
260- this [ CLOSE_PROMISE ] = closeFunction ( ) ;
261- return this [ CLOSE_PROMISE ] ;
247+ readyCallback ( name , opts ) {
248+ return this . lifecycle . legacyReadyCallback ( name , opts ) ;
262249 }
263250
264251 /**
265252 * Register a function that will be called when app close
266253 * @param {Function } fn - the function that can be generator function or async function
267254 */
268255 beforeClose ( fn ) {
269- assert ( is . function ( fn ) , 'argument should be function' ) ;
270- this [ CLOSESET ] . add ( fn ) ;
256+ this . lifecycle . registerBeforeClose ( fn ) ;
271257 }
272258
273259 /**
274- * @member {Function}
275- * @private
260+ * Close all, it will close
261+ * - callbacks registered by beforeClose
262+ * - emit `close` event
263+ * - remove add listeners
264+ *
265+ * If error is thrown when it's closing, the promise will reject.
266+ * It will also reject after following call.
267+ * @return {Promise } promise
268+ * @since 1.0.0
276269 */
277- [ INIT_READY ] ( ) {
278- /**
279- * register an callback function that will be invoked when application is ready.
280- * @method {Function} EggCore#ready
281- * @see https://github.com/node-modules/ready
282- * @since 1.0.0
283- * @example
284- * const app = new Application(...);
285- * app.ready(err => {
286- * if (err) throw err;
287- * console.log('done');
288- * });
289- */
290-
291- // get app timeout from env or use default timeout 10 second
292- const eggReadyTimeoutEnv = Number . parseInt ( process . env . EGG_READY_TIMEOUT_ENV || 10000 ) ;
293- assert ( Number . isInteger ( eggReadyTimeoutEnv ) , `process.env.EGG_READY_TIMEOUT_ENV ${ process . env . EGG_READY_TIMEOUT_ENV } should be able to parseInt.` ) ;
294-
295- /**
296- * If a client starts asynchronously, you can register `readyCallback`,
297- * then the application will wait for the callback to ready
298- *
299- * It will log when the callback is not invoked after 10s
300- *
301- * Recommend to use {@link EggCore#beforeStart}
302- * @method {Function} EggCore#readyCallback
303- * @since 1.0.0
304- * @example
305- * const done = app.readyCallback('mysql');
306- * mysql.ready(done);
307- */
308- require ( 'ready-callback' ) ( { timeout : eggReadyTimeoutEnv } ) . mixin ( this ) ;
309-
310- this . on ( 'ready_stat' , data => {
311- this . console . info ( '[egg:core:ready_stat] end ready task %s, remain %j' , data . id , data . remain ) ;
312- } ) . on ( 'ready_timeout' , id => {
313- this . console . warn ( '[egg:core:ready_timeout] %s seconds later %s was still unable to finish.' , eggReadyTimeoutEnv / 1000 , id ) ;
314- } ) ;
270+ async close ( ) {
271+ if ( this [ CLOSE_PROMISE ] ) return this [ CLOSE_PROMISE ] ;
272+ this [ CLOSE_PROMISE ] = this . lifecycle . close ( ) ;
273+ return this [ CLOSE_PROMISE ] ;
315274 }
316275
317276 /**
0 commit comments