-
Notifications
You must be signed in to change notification settings - Fork 92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: impl boot methods #171
Conversation
Codecov Report
@@ Coverage Diff @@
## master #171 +/- ##
======================================
Coverage 100% 100%
======================================
Files 18 20 +2
Lines 958 1068 +110
======================================
+ Hits 958 1068 +110
Continue to review full report at Codecov.
|
lib/egg.js
Outdated
} | ||
} | ||
|
||
ready(flagOrFunction) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个直接用 get-ready 吧
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里没法直接用 get-ready 的,就是上次讲过的 第二个 ready 对象需要延迟init
lib/egg.js
Outdated
/** | ||
* @member {BootClass} EggCore#BootClass | ||
*/ | ||
this.BootClass = BootClass; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
感觉没必要继承这个类
app.bootLog.push('didReady'); | ||
} | ||
|
||
async beforeClose() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个我们要调整吗,didClose
lib/loader/mixin/custom.js
Outdated
this.timing.end('Load app.js'); | ||
this.app[Symbol.for('EggCore#triggerConfigDidLoad')](); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个应该在 loadconfig 后
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
loadCustomApp 是在 loadConfig 之后的。
逻辑可以在整理下,这里 app 上比较乱,建议放到一个类里面去处理所有逻辑,比如 lifecycle
在 lifecycle 管理生命周期,lifecycle ready 后触发 app ready。app 现有的 api 可以直接调用这个类的 api 来注册 |
关注,puml 图也提交到 README 中,或者 egg 文档中。 |
ping @popomore 把生命周期的控制抽取到 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
先提这些
lib/lifecycle.js
Outdated
*/ | ||
initBoots() { | ||
this.boots = this.app[BOOT_FILES] | ||
.map(t => (is.function(t) && !is.class(t) ? t(this.app) : t)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里为啥还要执行下?应该就筛选出类
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
loadCustom 里面不再执行了,统一只执行了 requireFile , 所以这里执行了一下。兼容旧的方法的写法。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
还是分开吧,这里只处理 boot 类,那里保持原样。
lib/lifecycle.js
Outdated
this.triggerConfigDidLoad(); | ||
} | ||
|
||
beforeStart(scope) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里改成 registerDidLoad 吧,和 trigger 对应。
app 的 beforeStart 还是调用这个。
加一个 legacyReadyCallback 的 getter 调用 loadReady 的 readyCallback,然后 app 的 readyCallback 调用这个。
lib/lifecycle.js
Outdated
return this.closePromise; | ||
} | ||
|
||
ready(flagOrFunction) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里还是直接用 get-ready 吧
this.loadReady.ready(() => {
this.triggerWillReady()
})
this.bootReady.ready(() => {
this.ready(true)
});
这样把整个流程串起来
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
如果错误就直接调用 this.ready(err)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
app.ready
这个方法中传入的函数实际调用的是 bootReady,而 bootReady 是在 loadReady ready 之后才实例化的。所以 lifecycle 的 ready 方法不能直接由 ready 对象代理。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
app.ready 应该是应用完成 ready 后,不是注册到 bootReady
lib/lifecycle.js
Outdated
}); | ||
} | ||
|
||
beforeClose(fn) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个也改成 registerDidClose 吧
lib/lifecycle.js
Outdated
this.closeSet.add(fn); | ||
} | ||
|
||
close() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里改成 async 吧,然后判断下是否执行了两次
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个判断我加一下。不过是 break change 了,旧版本是可以 close 多次的。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
之前也不行只是返回相同的 promise,看看测试看
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
现在这里重复执行也是返回相同的 promise,判断不是抛出重复 close 异常的意思吗?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
改成 async 会更加简洁,现在还要有个闭包
lib/lifecycle.js
Outdated
.filter(t => t.didReady) | ||
.map(t => t.didReady.bind(t)); | ||
const readyCbs = [ | ||
...this.readyCallbacks, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里只需要处理 boot 类的就好了,直接进入到 lifecycle 的 ready 阶段了,开发者自己坚挺 app.ready 不需要我们处理了
lib/egg.js
Outdated
@@ -123,6 +122,7 @@ class EggCore extends KoaApplication { | |||
logger: this.console, | |||
serverScope: options.serverScope, | |||
}); | |||
this[BOOT_FILES] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个有用?
lib/loader/mixin/custom.js
Outdated
continue; | ||
} | ||
const file = this.requireFile(filePath); | ||
this.app[BOOT_FILES].push(file); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
直接用 lifecycle 的 api?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个阶段应该在 didConfigLoad 之后了,我绝对 loader 最开始可以先加载 boot 文件,然后到这里才执行函数。
lib/egg.js
Outdated
app: this, | ||
logger: this.console, | ||
}); | ||
this.lifecycle.on('error', this.emit.bind(this, 'error')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
用 error => this.emit('error', error)
的写法吧,可以不用 bind 了
lib/lifecycle.js
Outdated
return this.app.timing; | ||
} | ||
|
||
get legacyReadyCallback() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
直接用函数呗,bind 比较丑
lib/lifecycle.js
Outdated
*/ | ||
initBoots() { | ||
this.boots = this.bootFiles.map(t => new t(this.app)); | ||
this[REGISTER_BEFORE_CLOSE](); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
是不是可以在这里把所有的都给注册一遍
for (const boot of this.boots) {
if (boot.didLoad) {
this.didLoadSet.add(boot.didLoad);
}
if (boot.willReady) {
this.willReadySet.add(boot.willReady);
}
// ...所有生命周期
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个没什么必要吧,单独把 function 存起来又要用 bind 了。
lib/lifecycle.js
Outdated
this.closeSet.add(fn); | ||
} | ||
|
||
close() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
改成 async 会更加简洁,现在还要有个闭包
lib/lifecycle.js
Outdated
this.loadReady.ready(error => { | ||
debug('didLoad done'); | ||
if (error) { | ||
this.triggerDidReady(error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
如果 error 这里就不用触发了吧
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
triggerDidReady 同样是通过 this.ready(err => this.triggerDidReady(err)) 触发的
lib/lifecycle.js
Outdated
}); | ||
} | ||
|
||
[INIT_BOOT_READY]() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个和 INIT_LOAD_READY 应该是类似的,这里有些差异,比如 readyTimeout 和 stat
lib/lifecycle.js
Outdated
/** | ||
* init boots and trigger config did config | ||
*/ | ||
initBoots() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个在哪里调用的
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
由 loader 在 loadCustomApp/loadCustomAgent 结束后调用
initBoots 的位置还是不对,应该在 customApp 前面,比如在 configDidLoad 修改中间件,app.js 里面应该可以取到最新的。 |
@popomore 改对了,测试用例里面也加入了这种情况。 |
a273973
to
451d41f
Compare
lib/lifecycle.js
Outdated
} | ||
|
||
[INIT_BOOT_READY]() { | ||
if (!this.bootReady) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里会调用两次?
lib/lifecycle.js
Outdated
this[REGISTER_READY_CALLBACK](didLoad, this.loadReady, 'Did Load'); | ||
} | ||
} | ||
this.loadReady.ready(err => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个是不是可以移到 INIT_LOAD_READY 去,定义和 trigger 分开。
lib/lifecycle.js
Outdated
|
||
[INIT_BOOT_READY]() { | ||
if (!this.bootReady) { | ||
this.bootReady = new Ready({ timeout: this.readyTimeout }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lib/loader/mixin/custom.js
Outdated
}, | ||
|
||
loadBootFile(fileName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我又想了下,是不是增加一个 config.initBoot() 的方法,用来加载 app.js/agent.js,这个方法放到 config.loadPlugin 之后。
lib/lifecycle.js
Outdated
await boot.didReady(err); | ||
} | ||
} catch (e) { | ||
this.app.emit('error', e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个不用 this.emit?
lib/lifecycle.js
Outdated
(async () => { | ||
for (const boot of this.boots) { | ||
try { | ||
if (boot.didReady) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if 放到外面去
lib/egg.js
Outdated
}).on('ready_timeout', id => { | ||
this.console.warn('[egg:core:ready_timeout] %s seconds later %s was still unable to finish.', eggReadyTimeoutEnv / 1000, id); | ||
}); | ||
boot() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个 API 是不是可以不需要了,triggerDidLoad 应该在 app.js 里面就触发了?
egg 文档也改起来,加上这个章节 👍 |
这个 app.js/agent.js 我想想还是不拿出来了,app.js/agent.js 加载是有特殊性的,appWrokerLoader 只加载 app.js,agentWrokerLoader 只加载 agent.js。现在是通过方法的方式来区分的,而在 EggLoader 自身是区分不出是 appWorkerLoader 还是 agentWorkerLoader 的,不能做到只加载需要的文件。 |
ping @popomore |
* @see https://github.com/node-modules/ready | ||
* @since 1.0.0 | ||
* @param {boolean|Error|Function} flagOrFunction - | ||
* @return {Promise|null} return promise when argument is undefined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
啥时会返回 null ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
应该推荐使用 await app.ready()
的方式而不是 callback 的方式?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
使用 ready(() => {})
的时候是返回 null 的。这里是保证接口的兼容性。
lib/egg.js
Outdated
this.console.warn('[egg:core:ready_timeout] %s seconds later %s was still unable to finish.', eggReadyTimeoutEnv / 1000, id); | ||
}); | ||
async close() { | ||
if (this.closePromise) return this.closePromise; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
closePromise
是内部变量?用 Symbol 或 _ ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个可以有。
lib/lifecycle.js
Outdated
|
||
const utils = require('./utils'); | ||
|
||
class Lifecycle extends EventEmitter { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
要不要继承 sdk-base 啥的? @popomore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个 Lifecycle 和 SDKBase 还不太一样,SDKBase 一般是异步 init 的时候用一下。
this.timing.start('Application Start'); | ||
// get app timeout from env or use default timeout 10 second | ||
const eggReadyTimeoutEnv = Number.parseInt(process.env.EGG_READY_TIMEOUT_ENV || 10000); | ||
assert( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 这句应该在上面的 parseInt 前面?
Number.isInteger
用 is-type-of ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parseInt
之后才能使用Number.isInteger
- 这个
Number.isInteger
还用 is-type-of 就没什么必要了吧。
|
||
this[INIT_READY](); | ||
this | ||
.on('ready_stat', data => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ready_done / ready_suc 会不会好点?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个是 ready-callback emit 过来的事件了,不好改了。
lib/lifecycle.js
Outdated
init() { | ||
assert(this[INIT] === false, 'lifecycle have been init'); | ||
this[INIT] = true; | ||
this.boots = this.bootFiles.map(t => new t(this.app)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个 t
是一个 class ? 上面的 addBootFile
是一个 file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
是一个 class,在 customLoader 里面有这样一个判断 is.class(bootFile)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
那 addBootFile
这个命名会不会有点误导? addBootHook(Clz)
这样是不是好点?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
是有点误导,改了。
lib/lifecycle.js
Outdated
|
||
registerBeforeClose(fn) { | ||
assert(is.function(fn), 'argument should be function'); | ||
assert(this.isClose === false, 'app has been closed'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isClosed ? 不过要看看之前的风格
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
之前就是 isClose 😂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
不过还是改一下吧。改一下合理一点
1. add `Boot` Class, developer can inherit from it. 2. add `startBoot`, application like egg should call `startBoot` after all files loaded. Refs: eggjs/egg#2520
+1 |
lifecycle 内部 beforeClose 钩子保存在一个 Set 里面是出于什么考虑?私以为用数组貌似也可以? |
@initial-wu 可以防止重复添加。 |
明白。btw,考虑调整一下这里的写法吗 #171 (comment) |
没明白你说的意思。 |
这个评论的锚点应该已经变了,@popomore 可能是想说改成这样? |
之前说的就是你截图的地方,这里不用在封装一遍了,会多一层调用栈。 |
1. Add `Lifecycle` class, control EggCore lifecycle. 2. After config, extend, app.js, angent.js loaded, loader should call `initBoots`. 3. After all files loaded, loader should call `triggerDidLoad`. Refs: eggjs/egg#2520
Lifecycle
class, control EggCore lifecycle.initBoots
.triggerDidLoad
.Refs: eggjs/egg#2520
Checklist
npm test
passesAffected core subsystem(s)
Description of change