如何解决使用 Yarn PNP 构建部署时在 PM2 集群模式下运行 NestJS 从 npm 迁移到 yarn pnpPM2
从 npm 迁移到 yarn pnp
几个月前,我们开始为我们的 monorepo 使用 yarn2 (pnpify),因为 node_modules 确实增长到 200K 包。多亏了 yarn2,我们将所有包的构建和部署时间从 40 分钟减少到 4-5 分钟,这真是太棒了。
前端包很容易被摇树和捆绑,以创建一个小工件并上传到存储容器。
为了在集群模式下使用 pm2 运行构建,后端包(nestjs Rest 和 GraphQl API)有点棘手。
PM2
使用 PM2,您可以在 fork
或 cluster
模式下运行您的应用。
在同一端口上运行您的应用时,您需要使用 cluster
模式。Fork
模式在启动第一个 fork 后一直说端口已在使用中(这是完全合法的)
由于我们使用了yarn2,因此我们只能使用yarn作为解释器运行我们的应用程序:
yarn node ./build/main.js
为了有适当的模块分辨率,因为节点不理解它。
问题来了:
yarn(和 npm)在集群模式下表现不佳。
这是因为您需要使用 node 本身作为解释器,而不是 yarn(或 npm)
所以我们最终得到了以下生态系统.config.js
{
"apps": [
{
"args": "node ./build/main.js","exec_mode": "cluster","instances": "max","interpreter": "bash","name": "api","script": "yarn","time": true
}
]
}
我们将部署交付到具有 1 个以上 cpu 内核的虚拟机,并使用新生态系统重新加载了 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,以便我们可以将应用程序作为真正的节点进程运行?
有没有办法在使用 yarn 作为解释器的同时在同一端口以集群模式运行 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 种可能的功能解决方案:
- yarn2 将能够在构建步骤后弹出 .yarn 缓存以重新创建 node_modules,以便在 npm 中启动您的应用。
- pm2 将添加一项功能,以与集群模式结合使用纱线而不是 npm 启动您的应用
更新
你不需要纱线来运行具有纱线模块分辨率的应用程序。
您唯一需要做的就是在使用 node 作为解释器运行应用程序时需要 .pnp.js
。
将 "interpreter_args": "--require /path/to/.pnp.js",
添加到您的 pm2 配置
ecosystem.config.js:
{
"apps": [
{
"name": "my-app","script": "./main.js","interpreter_args": "--require /path/to/.pnp.js","exec_mode": "cluster"
}
]
}
现在您可以执行 pm2 start ecosystem.config.js
而不会遇到任何关于未找到节点模块的错误。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。