[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服务以及网关服务 就可以成功调用了

相关推荐
A尘埃20 分钟前
大模型应用python+Java后端+Vue前端的整合
java·前端·python
码事漫谈1 小时前
从后端开发者到Agent工程师:一份系统性的学习指南
后端
遥遥晚风点点1 小时前
Spark导出数据文件到HDFS
前端·javascript·ajax
码事漫谈1 小时前
后端开发如何将创新转化为专利?案例、流程与实操指南
后端
克里斯蒂亚L1 小时前
开发一个计时器组件
前端·浏览器
克里斯蒂亚诺更新1 小时前
微信小程序 点击某个marker改变其大小
开发语言·前端·javascript
天才奇男子2 小时前
从零开始搭建Linux Web服务器
linux·服务器·前端
小坏讲微服务2 小时前
SpringCloud零基础学全栈,实战企业级项目完整使用
后端·spring·spring cloud
长空任鸟飞_阿康2 小时前
AI 多模态全栈应用项目描述
前端·vue.js·人工智能·node.js·语音识别
Mintopia2 小时前
🌐 实时协同 AIGC:多人在线 Web 创作的技术架构设计
前端·人工智能·trae