我正在使用 Bull 实现 NestJS 工作线程 queues。
根据文档,工作程序和服务器(将)在同一个“进程”中运行,但我想在单独的进程中运行工作程序,以便不阻塞主事件循环。
我认为这被称为“在单独的二进制文件中运行任务”或其他名称。
无论如何,我尝试用谷歌搜索它,浏览NestJS的文档,但找不到类似的东西。
++ 换句话说:
我有一个主项目(我当前的),我想在单独的进程(独立应用程序)中创建工作人员,并希望连接我当前的主项目和工作人员。我在文档中找不到它。
我应该在哪个模块中实例化我的 Bull 实例?我假设我会将
producer
保留在我的主模块中,将 consumer
保留在我的工作模块中。
我该怎么做?
请注意,“单独的进程”并不是指在单独的进程中运行特定任务,如 Bull 的 documentation 中所定义。 我想将整个工作模块部署在一个单独的进程中或任何应该使用的术语中。
++ [如果可能的话,额外的]
在运行我的服务器和worker之前,我还想检查我的worker(公牛实例)是否成功连接到我的Redis服务器。我在 Bull 的文档中找不到任何内容...您认为有一个好的解决方法吗?
您可以使用该文档来实现整个工作人员。如果您在独立模式下使用 Nest.js,您可以只拥有处理器和进程。
这已记录在此处。 “单独的二进制文件”也不是问题。二进制文件是编译的产物,Node.js 未编译,因此您需要一个单独的应用程序。
您不需要解决任何问题,这就是 Bull 和可选的 Nest.js 的本质。
有时您需要调整文档中的示例来满足您的需求,这可能需要一些时间来学习。
我认为术语有些混乱,所以在这篇文章中假设:
process
是您的 application
在内部运行的内容(如果您查看操作系统进程管理器,它应该是 node
)。application
是 one Node.js 项目,在单独的 process
中运行。worker
是一个 application
,它仅专注于处理队列作业。Queue
和 Job
是 Bull 的术语。Processor
和 Process
是 Nest.js 的术语 @nestjs/bull
以下是如何创建 application 以及在单独进程中运行的 worker。按照这些说明操作后,您应该看到两个进程正在运行您的进程管理器。
创建一个新的 Nest.js 应用程序,我们将用于您的
worker
:
nest new my-worker
打开
src/main.ts
并将 bootstrap
函数中的所有内容替换为:
const app = await NestFactory.createApplicationContext(AppModule);
安装
Bull
和 Nest.js 实现:
yarn add @nestjs/bull bull
打开
src/app.module.ts
并从 AppController
中删除 controllers
,然后将 BullModule.registerQueue
添加到导入中(来自 @nestjs/bull
。
您的
src/app.module.ts
现在应如下所示:
// app.module.ts
// ... imports
@Module({
imports: [
BullModule.registerQueue({
name: 'my-queue',
redis: {
host: 'localhost',
port: 6379,
},
}),
],
})
export class AppModule {}
在
app.processor.ts
目录中创建一个新文件:src
:
// app.processor.ts
// ... imports
@Processor('my-queue')
export class AppConsumer {
@Process('namedjob')
async processNamedJob(job: Job<any>): Promise<any> {
// do something with job and job.data
}
}
事情的
worker
方面你已经完成了。现在您需要做的就是在您的 application
(主项目)中,更新您的 AppModule
以包含 BullModule.registerQueue
(如上)并注入它:
export class MyService {
constructor(@InjectQueue('my-queue') private queue: Queue) {}
}
然后使用
this.queue.add('namedJob', data);
尝试上面的方法,如果你遇到困难,请在 Github 上创建一个存储库,我会让你走上正轨。
目标:水平扩展✅
虽然Isolated提供的答案应该有效,但我不想运行一个全新的项目并按照他们的建议导入我的模块。因此,经过更多的研发,我找到了一种不同的方法。
就像我们的“父”项目有
index.ts
或 main.ts
文件一样,在同一目录中(不一定是),创建一个 worker.ts
和 worker.module.ts
。
在
worker.module.ts
中,请确保注册您的 Bull 模块 again [BullModule.forRoot({})
] 并包含您的消费者所需的所有导入。
在
providers
中,您应该添加我们的consumers
,然后就可以开始了。
worker.ts
看起来像这样(没什么特别的):
import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
import { WorkerModule } from './worker/worker.module';
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(WorkerModule);
app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));
process.env.WORKER_HTTP_PORT = process.env.WORKER_HTTP_PORT ?? '4001';
await app.listen(process.env.WORKER_HTTP_PORT);
console.debug(`Worker is running on ${await app.getUrl()}`);
}
bootstrap();
你的
nest-cli.json
应该喜欢这样的东西
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"entryFile": "main",
"compilerOptions": {
"assets": ["**/*.graphql"],
"watchAssets": true
}
}
并创建一个新的
nest-cli-worker.json
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"entryFile": "worker",
"compilerOptions": {
"watchAssets": true
}
}
现在的问题是,如何运行它?
我正在使用
yarn
命令来启动我的服务器(在 package.json
中定义它们)
致
start
我的server
,我会
"start:dev": "yarn nest start --watch -e 'node -r dotenv/config -r source-map-support/register'"
或
"start:prod": "node -r dotenv/config -r ./tsconfig-paths-bootstrap.js dist/src/main.js"
对于
start
我的worker
,我会在另一个(终端)shell中运行以下命令...
开发
"worker:start:dev": "yarn nest start --config nest-cli-worker.json --watch -e 'node -r dotenv/config -r source-map-support/register'"
或
产品
"worker:start:prod": "node -r dotenv/config -r ./tsconfig-paths-bootstrap.js dist/src/worker.js"
P.S 您不一定要添加
dotenv/config
。
奖金:
如果您想在
运行您的服务器docker
这是我的
docker-compose.yaml
文件
version: '3.8'
services:
main:
container_name: my-server
image: xxx.amazonaws.com/xx/xxx:${CONTAINER_IMAGE_TAG:-latest}
ports:
- 80:80
command: node -r dotenv/config -r ./tsconfig-paths-bootstrap.js dist/src/main.js #My `prod` command for main server
volumes:
- xxx
links:
- xxx
environment:
xxx
# .env is generated by Elastic Beanstalk, don't provide one
env_file:
- .env
worker:
container_name: worker-server #YOUR WORER
image: xxx.us-west-2.amazonaws.com/xxx:${CONTAINER_IMAGE_TAG:-latest}
ports:
- 90:90
links:
- xxx
command: node -r dotenv/config -r ./tsconfig-paths-bootstrap.js dist/src/worker.js #prod command for Worker
volumes:
- xxx
environment:
xxx
# .env is generated by Elastic Beanstalk, don't provide one
env_file:
- .env