[NestJS] 手摸手~工作队列模式的邮件模块解析以及grpc调用

在 NestJS 中使用队列发送邮件可以提高系统的响应速度,避免因为邮件发送的延迟而阻塞主业务逻辑。我们可以使用 @nestjs/bull 包来处理队列,它基于 Redis。 步骤:

  1. 安装必要的依赖
  2. 配置Redis和Bull队列
  3. 创建邮件模块,包括邮件服务、队列处理器、队列服务
  4. 创建邮件模板
  5. 创建控制器
  6. 环境配置

创建以下文件:

  1. app.module.ts - 根模块
  2. app.service.ts - 邮件服务&队列服务(使用队列)
  3. app.processor.ts - 队列处理器(执行发送邮件)
  4. app.controller.ts - 控制器
  5. 模板文件(如welcome.hbs)

项目结构

css 复制代码
src/
├── main.ts
├── app.module.ts
├── app.processor.ts
├── app.service.ts
├── app.controller.ts
└── templates/
    ├── welcome.hbs

第一步:安装工作队列依赖

bash 复制代码
npm install --save @nestjs/bull bull
npm install --save-dev @types/bull

第二步:在 AppModule 中导入 BullModule 并且进行注册

ts 复制代码
imports: [
    // 配置 Bull 模块
    BullModule.forRoot({
        redis: {
            host: '127.0.0.1',
            port: 6379,
        },
    }),
    // 注册队列
    BullModule.registerQueue({
        name: 'smtp',
    }),
],

第三步:创建邮件服务

ts 复制代码
@Injectable()
export class AppService {
  constructor(
      @InjectQueue('smtp') private readonly smtpQueue: Queue,
  ) {}

  async sendWelcomeEmail(data: SendEmailRequest) {
    const job = await this.smtpQueue.add('welcome', { data });
    return  { jobId: job.id };
  }

}

第四步:安装邮件的通信包以及 Handlebars 模板

bash 复制代码
npm install --save @nestjs-modules/mailer nodemailer
npm install --save handlebars

第五步:在 AppModule 中导入 nodemailer 并且进行注册

ts 复制代码
imports: [
    MailerModule.forRoot({
        transport:{
            host: 'smtp.qq.com',
            port: 465,
            secure: true, // use SSL if required
            auth: {
                user: '邮箱',//例如:***@qq.com
                pass: '权限码',
            },

        },
        defaults: {
            from: '"系统通知" <****@qq.com>',
        },
        template:{
            dir:join(__dirname,'templates'),
            adapter:new HandlebarsAdapter(),
        }


    }),
],

第六步:创建队列处理器 app.processor.ts 并且把任务处理交给app.module.ts中的providers

ts 复制代码
@Processor('smtp')
export class AppProcessor {
    constructor(private readonly mailerService: MailerService) {
        console.log('MailerService 已注入:', !!mailerService);
    }

    @Process('welcome')
    async sendWelcomeEmail(job: Job<{ data: SendEmailRequest }>) {
        console.log('开始处理 welcome 队列任务,数据:', job.data);
        const sendEmailData = job.data.data;
        try {
            await this.mailerService.sendMail(
                {
                    to: sendEmailData.to,
                    subject: sendEmailData.subject,
                    template:'welcome',
                    context:{
                        name:sendEmailData.metadata?.name || 'User',
                        currentYear: new Date().getFullYear(),
                    }
                }
            );
            console.log('邮件发送成功');
        } catch (error) {
            console.error('邮件发送失败:', error.message);
        }

    }
}
ts 复制代码
providers: [AppProcessor,AppService],

最后是创建控制器

ts 复制代码
@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Post()
  async sendEmail(@Body() data: SendEmailRequest) {
    console.log('接收到的请求数据:', data);
    await this.appService.sendWelcomeEmail(data);
  }

}

然后通过grpc的email微服务

在资源目录下创建proto文件,创建需要用到的字段

proto 复制代码
syntax = "proto3";

package email;

service EmailService {
    rpc Send (SendEmailRequest) returns (SendEmailResponse) {};
}

message SendEmailRequest {
    string from = 1;
    string to = 2;
    string subject = 3;
    string body = 4;
    map<string, string> metadata  = 5;

}
message SendEmailResponse {
    bool success = 1;
    string message = 2;
}

还需要安装解析依赖以及grpc

bash 复制代码
 npm i --save @grpc/grpc-js @grpc/proto-loader
 //需要ts的话可以安装
 npm install nestjs-proto-gen-ts

并且添加脚本

json 复制代码
"proto:gen": "tsproto --path src/proto --output ./src/types",

运行proto:gen 可以在资源目录在获取ts文件

微服务搭建需要安装

bash 复制代码
 npm install  @nestjs/microservices    

在入口文件中搭建grpc服务

ts 复制代码
async function bootstrap() {
 const app = await NestFactory.createMicroservice(AppModule,{
   transport: Transport.GRPC,//选择grpc通信
   options: {
     package: 'email',//包名,注意一定要跟proto中的保持一致
     protoPath:join(__dirname,'proto/email.proto'),//proto文件的目录
     url:'0.0.0.0:8001'
   },
 });
 await app.listen();
 console.log('🚀 Email service is running on port 8001');
}
bootstrap();

在控制器中调用

ts 复制代码
@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @GrpcMethod('EmailService','send')
  send(data:SendEmailRequest){
    console.log('接收到的请求数据:', data);
    return this.appService.sendWelcomeEmail(data);
  }
 }

接着在网关注册grpc客户端,也需要安装相同的依赖以及proto文件

ts 复制代码
@Module({
  imports: [
      ClientsModule.register([
        {
          name: 'EMAIL_SERVICE',
          transport: Transport.GRPC,
          options: {
            package: 'email',
            protoPath: join(__dirname, 'proto/email/email.proto'),
            url:'0.0.0.0:8001'
          },
        },
      ]),
      ]
   })

在email服务中使用

ts 复制代码
@Injectable()
export class EmailService implements OnModuleInit {
    private emailService: email.EmailService;
    constructor(@Inject('EMAIL_SERVICE') private emailCLIENT: ClientGrpc) {
    }

    onModuleInit(): any {
        this.emailService = this.emailCLIENT.getService<email.EmailService>('EmailService');
    }

    sendWelcomeEmail(data:email.SendEmailRequest){
        return this.emailService.send(data);
    }
}

最后在通过控制器

ts 复制代码
@Controller('email')
export class EmailController {
    constructor(private emailService: EmailService) {
    }

    @Post('send-welcome-email')
    sendWelcomeEmail(@Body() data:SendWelcomeEmailRequest){
        return this.emailService.sendWelcomeEmail(data);
    }
}

开启email服务以及网关服务 就可以成功调用了

相关推荐
俩毛豆3 小时前
【图片】【编缉】图片增加水印(通过组件的Overlay方法增加水印)
前端·harmonyos
唐叔在学习3 小时前
200kb能作甚?mss表示我给你整个截图程序
后端·python
gustt3 小时前
JS 变量那些坑:从 var 到 let/const 的终极解密
前端·javascript
用户8356290780513 小时前
用Python自动化转换PowerPoint幻灯片为图片
后端·python
Z_B_L4 小时前
问题记录--elementui中el-form初始化表单resetFields()方法使用时出现的问题
前端·javascript·vue.js·elementui·1024程序员节
袁煦丞4 小时前
PandaWiki开源知识库系统破解内网限制:cpolar内网穿透实验室第616个成功挑战
前端·程序员·远程工作
golang学习记4 小时前
Next.js MCP Server 实战指南:让 AI 编程助手真正“懂”你的应用
前端
柳鲲鹏4 小时前
多种方法:OpenCV中修改像素RGB值
前端·javascript·opencv·1024程序员节
susu10830189114 小时前
chrome浏览器设置为手机模式
前端·chrome