NestJS 在单独的进程中运行工作线程

Den*_*nis 19 worker nestjs

我正在使用Bull实现 NestJS 工作线程、队列

根据文档,工作程序和服务器(将)在同一个“进程”中运行,但我想在单独的进程中运行工作程序,以免阻塞主事件循环。

我认为这被称为“在单独的二进制文件中运行任务”或其他名称。

无论如何,我尝试用谷歌搜索它,浏览 NestJS 的文档,但找不到类似的东西。

++ 换句话说:

我有一个主项目(我当前的),我想在单独的进程(独立应用程序)中创建工作人员,并希望连接我当前的主项目和工作人员。而且我在文档中找不到它。

我应该在哪个模块中实例化我的 Bull 实例?我假设我会将其保留producer在主模块和consumer工作模块中。

我怎样才能这样做呢?

请注意,我所说的“单独进程”并不是指在单独进程中运行特定任务,如 Bull文档中所定义。我想将整个工作模块部署在一个单独的进程中或任何应该使用的术语中。

++ [额外,如果可能的话]

在运行我的服务器和worker之前,我还想检查我的worker(公牛实例)是否成功连接到我的Redis服务器。我在公牛的文档中找不到任何内容...您认为有一个好的解决方法吗?

Iso*_*ted 26

可以使用该文档来实现整个工作人员。如果您在独立模式下使用 Nest.js,您可以只拥有 Processor(s) 和 Process(es)。

\n

此处记录了这一点。\xe2\x80\x9c单独的二进制文件\xe2\x80\x9d 也不是\xe2\x80\x99t 问题。二进制文件是编译的产物,Node.js 不是\xe2\x80\x99 编译的,因此你\xe2\x80\x99 将需要一个单独的应用程序

\n

你不需要\xe2\x80\x99 来解决任何问题,这实际上是 Bull 和可选的 Nest.js 的本质。

\n

有时您\xe2\x80\x99需要调整文档中的示例来满足您的需求,这可能需要一些时间来学习。

\n

术语

\n

我认为术语有些混乱,所以在这篇文章中假设:

\n
    \n
  1. Aprocess是您application在内部运行的内容(如果您查看操作系统进程管理器,它应该是node)。
  2. \n
  3. Aapplication一个Node.js 项目,在单独的process.
  4. \n
  5. Aworker是仅application专注于处理队列作业的
  6. \n
  7. QueueJob公牛的术语。
  8. \n
  9. ProcessorProcessNest.js 的术语@nestjs/bull
  10. \n
\n

解决方案

\n

以下是如何创建一个应用程序,其中的工作线程在单独的进程中运行。按照这些说明操作后,您应该看到两个进程正在运行您的进程管理器。

\n

创建一个新的 Nest.js 应用程序,我们将用于您的worker

\n
nest new my-worker\n
Run Code Online (Sandbox Code Playgroud)\n

打开函数src/main.ts中的所有内容并将其替换bootstrap为:

\n
const app = await NestFactory.createApplicationContext(AppModule);\n
Run Code Online (Sandbox Code Playgroud)\n

安装Bull并使用 Nest.js 实现:

\n
const app = await NestFactory.createApplicationContext(AppModule);\n
Run Code Online (Sandbox Code Playgroud)\n

打开src/app.module.tsAppController从中删除controllers,然后添加BullModule.registerQueue到导入(来自@nestjs/bull.

\n

src/app.module.ts现在应该看起来像:

\n
yarn add @nestjs/bull bull\n
Run Code Online (Sandbox Code Playgroud)\n

app.processor.tssrc目录中创建一个新文件:

\n
// app.module.ts\n// ... imports\n@Module({\n  imports: [\n    BullModule.registerQueue({\n      name: \'my-queue\',\n      redis: {\n        host: \'localhost\',\n        port: 6379,\n      },\n    }),\n  ],\n})\nexport class AppModule {}\n
Run Code Online (Sandbox Code Playgroud)\n

你已经完成了worker事情的一部分。现在您需要做的就是在您的application(主项目)中,更新您的内容AppModule以包含BullModule.registerQueue(如上)并注入它:

\n
// app.processor.ts\n// ... imports\n@Processor(\'my-queue\')\nexport class AppConsumer {\n    @Process(\'namedjob\')\n    async processNamedJob(job: Job<any>): Promise<any> {\n        // do something with job and job.data\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

然后使用this.queue.add(\'namedJob\', data);

\n

尝试上面的方法,如果你遇到困难,请在 Github 上创建一个存储库,我会让你走上正轨。

\n

参考

\n
    \n
  1. https://github.com/OptimalBits/bull#separate-processes
  2. \n
  3. https://docs.nestjs.com/standalone-applications
  4. \n
\n


Den*_*nis 15

目标:水平缩放 \xe2\x9c\x85

\n

虽然isolated提供的答案应该有效,但我不想运行一个全新的项目并按照他的建议导入我的模块。因此,经过更多的研发,我找到了一种(更好的)方法来做到这一点。

\n

正如我们为“父”项目创建index.tsmain.ts文件一样,在同一目录中(不一定是),创建一个worker.tsworker.module.ts

\n

在 中worker.module.ts,请确保再次注册您的Bull模块[ ] 并包含您的消费者所需的所有导入。BullModule.forRoot({})

\n

在 中providers,您应该添加 our consumers,然后就可以开始了。

\n

看起来worker.ts像这样(没什么花哨的):

\n
import { NestFactory } from \'@nestjs/core\';\nimport { NestExpressApplication } from \'@nestjs/platform-express\';\nimport { WINSTON_MODULE_NEST_PROVIDER } from \'nest-winston\';\nimport { WorkerModule } from \'./worker/worker.module\';\n\nasync function bootstrap() {\n  const app = await NestFactory.create<NestExpressApplication>(WorkerModule);\n  app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));\n  process.env.WORKER_HTTP_PORT = process.env.WORKER_HTTP_PORT ?? \'4001\';\n  await app.listen(process.env.WORKER_HTTP_PORT);\n  console.debug(`Worker is running on ${await app.getUrl()}`);\n}\nbootstrap();\n
Run Code Online (Sandbox Code Playgroud)\n

nest-cli.json应该喜欢这样的东西

\n
{\n  "collection": "@nestjs/schematics",\n  "sourceRoot": "src",\n  "entryFile": "main",\n  "compilerOptions": {\n    "assets": ["**/*.graphql"],\n    "watchAssets": true\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

并创建一个新的nest-cli-worker.json

\n
{\n    "collection": "@nestjs/schematics",\n    "sourceRoot": "src",\n    "entryFile": "worker",\n    "compilerOptions": {\n        "watchAssets": true\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

现在的问题是,如何运行它?

\n

我正在使用yarn命令来启动我的服务器(在中定义它们package.json

\n

对于start我的server,我愿意

\n
"start:dev": "yarn nest start --watch -e \'node -r dotenv/config -r source-map-support/register\'"\n
Run Code Online (Sandbox Code Playgroud)\n

或者

\n
"start:prod": "node -r dotenv/config -r ./tsconfig-paths-bootstrap.js dist/src/main.js"\n
Run Code Online (Sandbox Code Playgroud)\n

对于start我的worker,我将在另一个(终端)shell 中运行以下命令...

\n
\n

开发者

\n
\n
"worker:start:dev": "yarn nest start --config nest-cli-worker.json --watch -e \'node -r dotenv/config -r source-map-support/register\'"\n
Run Code Online (Sandbox Code Playgroud)\n

或者

\n
\n

产品

\n
\n
"worker:start:prod": "node -r dotenv/config -r ./tsconfig-paths-bootstrap.js dist/src/worker.js"\n
Run Code Online (Sandbox Code Playgroud)\n

PS 你不一定要添加dotenv/config.

\n

奖金:

\n
\n

如果您想在以下位置运行您的服务器docker

\n
\n

这是我的docker-compose.yaml文件

\n
version: \'3.8\'\n\nservices:\n  main:\n    container_name: my-server\n    image: xxx.amazonaws.com/xx/xxx:${CONTAINER_IMAGE_TAG:-latest}\n    ports:\n      - 80:80\n    command: node -r dotenv/config -r ./tsconfig-paths-bootstrap.js dist/src/main.js #My `prod` command for main server\n    volumes:\n      - xxx\n    links:\n      - xxx\n    environment:\n      xxx\n    # .env is generated by Elastic Beanstalk, don\'t provide one\n    env_file:\n      - .env\n  worker:\n    container_name: worker-server #YOUR WORER\n    image: xxx.us-west-2.amazonaws.com/xxx:${CONTAINER_IMAGE_TAG:-latest}\n    ports:\n      - 90:90\n    links:\n      - xxx\n    command: node -r dotenv/config -r ./tsconfig-paths-bootstrap.js dist/src/worker.js  #prod command for Worker\n    volumes:\n      - xxx\n    environment:\n      xxx\n    # .env is generated by Elastic Beanstalk, don\'t provide one\n    env_file:\n      - .env\n
Run Code Online (Sandbox Code Playgroud)\n