Skip to content
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

docs(boot): update app start document #3348

Merged
merged 6 commits into from
Jan 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 64 additions & 21 deletions docs/source/en/basics/app-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,79 @@

When the application starts up, we often need to set up some initialization logic. The application bootstraps with those specific configurations. It is in a healthy state and be able to take external service requests after those configurations successfully applied. Otherwise, it failed.

The framework starts with a file called `app.js` that executes the application initialization logic, if present, and it returns a function.

For example, we need to load a list of national cities from the remote server during application startup for subsequent use in the controller:
The framework provides a unified entry file (`app.js`) for boot process customization. This file need returns a Boot class. We can define the initialization process in the startup application by defining the lifecycle method in the Boot class.

The framework has provided you several functions to handle during the whole [life cycle](../advanced/loader.md#life-cycles):

- `configWillLoad`: All the config files are ready to load, so this is the LAST chance to modify them.
- `configDidLoad`: When all the config files have been loaded.
- `didLoad`: When all the files have been loaded.
- `willReady`: When all the plug-ins are ready.
- `didReady`: When all the workers are ready.
- `serverDidReady`: When the server is ready.
- `beforeClose`: Before the application is closed.

We can defined Boot class in `app.js`. Below we take a few examples of lifecycle functions commonly used in application development:

```js
// app.js
module.exports = app => {
app.beforeStart(async () => {
// The lifecycle method runs before the application bootstraps
app.cities = await app.curl('http://example.com/city.json', {
method: 'GET',
dataType: 'json',
class AppBootHook {
constructor(app) {
this.app = app;
}

configWillLoad() {
// The config file has been read and merged, but it has not yet taken effect
// This is the last time the application layer modifies the configuration
// Note: This function only supports synchronous calls.

// For example: the password in the parameter is encrypted, decrypt it here
this.app.config.mysql.password = decrypt(this.app.config.mysql.password);
// For example: insert a middleware into the framework's coreMiddleware
const statusIdx = app.config.coreMiddleware.indexOf('status');
app.config.coreMiddleware.splice(statusIdx + 1, 0, 'limit');
}

async didLoad() {
// All configurations have been loaded
    // Can be used to load the application custom file, start a custom service

    // Example: Creating a custom app example
this.app.queue = new Queue(this.app.config.queue);
await this.app.queue.init();

// For example: load a custom directory
app.loader.loadToContext(path.join(__dirname, 'app/tasks'), 'tasks', {
fieldClass: 'tasksClasses',
});
}

// also could create an anonymous context to call Service
// const ctx = app.createAnonymousContext();
// app.cities = await ctx.service.cities.load();
});
};
```
async willReady() {
// All plugins have been started, but the application is not yet ready
    // Can do some data initialization and other operations
// Application will start after these operations executed succcessfully

`cities` attribute has attached on the global `app`. It can be accessed in the controller,
    // For example: loading data from the database into the in-memory cache
this.app.cacheData = await app.model.query(QUERY_CACHE_SQL);
}

```js
// app/controller/home.js
class HomeController extends Controller {
async index() {
// 'app.cities' is loaded, and you can access it by 'this.ctx.app.cities'
async didReady() {
// Application already ready

const ctx = await this.app.createAnonymousContext();
await ctx.service.Biz.request();
}

async serverDidReady() {
// http / https server has started and begins accepting external requests
    // At this point you can get an instance of server from app.server

app.server.on('timeout', socket => {
// handle socket timeout
});
}
}
```

**Note: When the framework executes the lifecycle method `beforeStart`, do not run time-consuming operation. The framework enables a *Timeout* setting by default when it starts up.**
**Note: It is not recommended to do too time-consuming operations in the custom lifecycle function, the framework will have a startup timeout detection.**
83 changes: 63 additions & 20 deletions docs/source/zh-cn/basics/app-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,77 @@ title: 启动自定义

我们常常需要在应用启动期间进行一些初始化工作,等初始化完成后应用才可以启动成功,并开始对外提供服务。

框架提供了统一的入口文件(`app.js`)进行启动过程自定义,这个文件只返回一个函数。例如,我们需要在应用启动期间从远程接口加载一份全国城市列表,以便于后续在 Controller 中使用:
框架提供了统一的入口文件(`app.js`)进行启动过程自定义,这个文件返回一个 Boot 类,我们可以通过定义 Boot 类中的生命周期方法来执行启动应用过程中的初始化工作。

框架提供了这些 [生命周期函数](../advanced/loader.md#life-cycles)供开发人员处理:

- 配置文件即将加载,这是最后动态修改配置的时机(`configWillLoad`)
- 配置文件加载完成(`configDidLoad`)
- 文件加载完成(`didLoad`)
- 插件启动完毕(`willReady`)
- worker 准备就绪(`didReady`)
- 应用启动完成(`serverDidReady`)
- 应用即将关闭(`beforeClose`)

我们可以在 `app.js` 中定义这个 Boot 类,下面我们抽取几个在应用开发中常用的生命周期函数来举例:

```js
// app.js
module.exports = app => {
app.beforeStart(async () => {
// 应用会等待这个函数执行完成才启动
app.cities = await app.curl('http://example.com/city.json', {
method: 'GET',
dataType: 'json',
class AppBootHook {
constructor(app) {
this.app = app;
}

configWillLoad() {
// 此时 config 文件已经被读取并合并,但是还并未生效
// 这是应用层修改配置的最后时机
// 注意:此函数只支持同步调用

// 例如:参数中的密码是加密的,在此处进行解密
this.app.config.mysql.password = decrypt(this.app.config.mysql.password);
// 例如:插入一个中间件到框架的 coreMiddleware 之间
const statusIdx = app.config.coreMiddleware.indexOf('status');
app.config.coreMiddleware.splice(statusIdx + 1, 0, 'limit');
}

async didLoad() {
// 所有的配置已经加载完毕
// 可以用来加载应用自定义的文件,启动自定义的服务

// 例如:创建自定义应用的示例
this.app.queue = new Queue(this.app.config.queue);
await this.app.queue.init();

// 例如:加载自定义的目录
app.loader.loadToContext(path.join(__dirname, 'app/tasks'), 'tasks', {
fieldClass: 'tasksClasses',
});
}

// 也可以通过以下方式来调用 Service
// const ctx = app.createAnonymousContext();
// app.cities = await ctx.service.cities.load();
});
};
```
async willReady() {
// 所有的插件都已启动完毕,但是应用整体还未 ready
// 可以做一些数据初始化等操作,这些操作成功才会启动应用

在 Controller 中就可以使用了:
// 例如:从数据库加载数据到内存缓存
this.app.cacheData = await app.model.query(QUERY_CACHE_SQL);
}

```js
// app/controller/home.js
class HomeController extends Controller {
async index() {
// 'app.cities' 在上面启动期间已经加载,可以直接通过 'this.ctx.app.cities' 使用。
async didReady() {
// 应用已经启动完毕

const ctx = await this.app.createAnonymousContext();
await ctx.service.Biz.request();
}

async serverDidReady() {
// http / https server 已启动,开始接受外部请求
// 此时可以从 app.server 拿到 server 的实例

app.server.on('timeout', socket => {
// handle socket timeout
});
}
}
```

**注意:在 `beforeStart` 中不建议做太耗时的操作,框架会有启动的超时检测。**
**注意:在自定义生命周期函数中不建议做太耗时的操作,框架会有启动的超时检测。**