[英]Running NestJS in PM2 cluster mode when building a deployment with Yarn PNP
幾個月前,我們開始在我們的 monorepo 中使用 yarn2 (pnpify),因為 node_modules 確實增長到了 200K 包。 多虧了 yarn2,我們將所有包的構建和部署時間從 40 分鍾減少到了 4-5 分鍾,這真的很棒。
前端包很容易進行 tree-shaking 和捆綁,以創建一個小工件並上傳到存儲容器。
后端包(Nestjs Rest & GraphQl API)有點棘手,以便在集群模式下使用 pm2 運行構建。
使用 PM2,您可以在fork
或cluster
模式下運行您的應用程序。
在同一端口上運行您的應用程序時,您需要使用cluster
模式。
Fork
模式在啟動第一個分叉后一直說端口已在使用中(這是完全合法的)
由於我們使用的是yarn2,我們只能使用yarn作為解釋器來運行我們的應用程序,方法是:
yarn node ./build/main.js
為了有適當的模塊解析,因為節點不理解它。
問題來了:
yarn(和 npm)在集群模式下表現不佳。
這是因為您需要使用節點本身作為解釋器而不是紗線(或 npm)
所以我們最終得到了以下的生態系統.config.js
{
"apps": [
{
"args": "node ./build/main.js",
"exec_mode": "cluster",
"instances": "max",
"interpreter": "bash",
"name": "api",
"script": "yarn",
"time": true
}
]
}
我們將部署發送到具有超過 1 個 CPU 內核的 VM,並使用新的生態系統重新加載 pm2 服務。 一切都保持綠色,但我們注意到只有 1 個進程實際上正在偵聽端口 3000,而所有其他進程確實拋出了EADDRINUSE
錯誤。 yarn 發出錯誤,而不是拋出它,所以 PM2 認為應用程序仍然存在。
或者至少,這是我們的結論……
捆綁 NestJS 是不可行的: bundled-nest
我唯一的解決方案是通過執行以下操作來集群化 nestjs 本身:
import { Injectable } from '@nestjs/common';
import { fork, isMaster, on } from 'cluster';
import * as os from 'os';
const numCPUs = os.cpus().length;
// const randomNumber = (min: number, max: number) =>
// Math.floor(Math.random() * max) + min;
@Injectable()
export class ClusterService {
// eslint-disable-next-line @typescript-eslint/ban-types
static clusterize(callback: Function): void {
if (isMaster) {
// eslint-disable-next-line no-plusplus
for (let i = 0; i < numCPUs; i++) {
fork();
}
on('exit', (worker, code) => {
fork();
// eslint-disable-next-line no-console
console.log(
`[Cluster] worker[${worker.process.pid}] died with status: [${code}], creating new worker`,
);
});
} else {
callback();
}
}
}
並在單個實例上運行 PM2,但這感覺有點古怪,因為 PM2 可以為您做到這一點……以更好的方式。
有沒有辦法用 yarn2 “彈出” node_modules 以便我們可以將應用程序作為真正的節點進程運行?
有沒有辦法在使用紗線作為解釋器的同時在同一端口上以集群模式運行 PM2?
如何在 yarn2 中拋出錯誤而不是發出錯誤,以便 PM2 將創建一個新進程?
...或者是否有另一種解決方案可以在 gitlab 中僅使用 npm 而不必等待 40 分鍾來構建包並使用節點解釋器 n pm2 運行 nestjs 應用程序?
yarn exec pm2 start ecosystem.config.js
並且不保存 pm2 進程。 pm2 只能在 npm 模式下復活,不會在 yarn 模式下執行你的腳本。
缺點是您不能使用 pm2 啟動來從 pm2 重新啟動。 所以你需要自己實現一個 systemd 服務,它將在啟動時執行一個yarn pm2:start
2 種可能的功能解決方案:
更新
您不需要 yarn 來運行具有 yarn 模塊分辨率的應用程序。
您唯一需要的是在使用節點作為解釋器運行應用程序時需要.pnp.js
。 將"interpreter_args": "--require /path/to/.pnp.js",
添加到您的 pm2 配置中
生態系統.config.js:
{
"apps": [
{
"name": "my-app",
"script": "./main.js",
"interpreter_args": "--require /path/to/.pnp.js",
"exec_mode": "cluster"
}
]
}
現在您可以執行pm2 start ecosystem.config.js
而不會遇到任何有關未找到節點模塊的錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.