eggjs / eggjs/egg

[RFC] egg readiness 改造

Open
#3,757 8 comments 4 reactions 1 assignee Claimed by @killagu View on GitHub
type: proposals
Dominant language
TypeScript
Stars
19k
Forks
1.8k
PR merge metrics
No merged PRs in 30d

Description

# 背景

## readiness 定义

>https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/
liveness: The kubelet uses liveness probes to know when to restart a Container. For example, liveness probes could catch a deadlock, where an application is running, but unable to make progress. Restarting a Container in such a state can help to make the application more available despite bugs.
readiness: The kubelet uses readiness probes to know when a Container is ready to start accepting traffic. A Pod is considered ready when all of its Containers are ready. One use of this signal is to control which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers.

简单来说 liveness 代表应用是不是挂了,readiness 代表应用是不是可访问的。

# 启动

## 启动依赖

目前 egg 使用 ready 来代表插件是否启动完成,应用是否启动完成。目前在插件依赖关系复杂的情况下,应用启动时间很长。原因是不管什么插件,是否是弱依赖的,都需要准备完成。而事实上是部分插件在不 ready 的情况下应用也应该是可访问的。

举个例子:有个缓存插件,会阻塞应用启动。但是业务场景是无缓存的时候可以 fallback 到 db 去。

```js
// cache-plugin
// app.js
module.exports = () => {
app.beforeStart(async () => {
await app.cache.ready();
});
};

// cache.js
module.exports = app => {
return class Cache extends Base {
async _init() {
await app.cacheConn.ready();
}

async fetchCache(key) {
return app.cacheConn.get(key);
}
}
};
```

可以做如下修改,在弱依赖的时候,不阻塞应用的启动。

```js
// config.default.js
module.exports = {
const config = {
cache: {
dependency: false,
},
};
return config;
};

// sdk-base.js
...
async ready() {
if (this.options.dependency === false) {
return true;
}
...
}

get isReady() {
...
}
...

// cache.js
module.exports = app => {
return class Cache extends Base {
async _init() {
await app.cacheConn.ready();
}

async fetchCache(key) {
return app.cacheConn.isReady && app.cacheConn.get(key);
}
}
};
```

## 启动过程

目前的启动过程是,master 会去监听 cluster 的 listening 事件,在 worker 监听了正确的端口之后,就会认为启动是完成了。
按照 liveness 和 readiness,应该是 worker 在启动时候就要开始监听端口,liveness 是通了,然后会去访问 worker 的 readiness 接口判断是否 ready 了。
但是受限于 node 的多进程模型,可能 worker 进程的状态是不一致的,所以需要 master 进程对状态做聚合。
- master 进程存活,则 liveness 是通的
- 有一个 worker 进程不是 readiness 的,则 readiness 就是不通的

# 访问
> Readiness probes runs on the container during its whole lifecycle.

目前的 ready 在应用启动完成之后就没有用了,但是 readiness 是在整个生命周期中都是会调用的。所以 ready 接口在插件、应用的状态发生改变之后,也需要做出变化,体现在 readiness 的返回结果上。

cc: @eggjs/core

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.