You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义Provider使用SqsService时无法解析SQS_OPTIONS依赖求助

问题分析

报错核心原因是SQS_OPTIONS是@ssut/nestjs-sqs的SqsModule内部提供的私有依赖,你的CoreModule未导入SqsModule,导致Nest无法在模块上下文中找到该依赖。同时要实现本地/生产队列切换的解耦目标,需要完善QueueResolver的多实现逻辑。

解决方案步骤

1. 完善QueueResolver的多实现

补充本地开发用的绕过队列实现,同时添加根据环境动态选择Provider的逻辑:

// queue.resolver.ts
import { SqsService } from '@ssut/nestjs-sqs';
import { SqsOptions } from '@ssut/nestjs-sqs/dist/sqs.types';
import { DiscoveryService } from '@golevelup/nestjs-discovery';
import { SQS_OPTIONS } from '@ssut/nestjs-sqs/dist/sqs.constants';
import { ConfigService } from '@nestjs/config';

export interface QueueResolver {
  send(queue: string, message: any): Promise<any>;
}

// 本地开发用:绕过队列直接处理消息
export class LocalQueueResolver implements QueueResolver {
  async send(queue: string, message: any): Promise<any> {
    console.log(`[LocalQueue] 跳过队列,直接处理: 队列=${queue}, 内容=${JSON.stringify(message)}`);
    // 可根据需求直接调用消息处理逻辑,或仅打印日志
    return Promise.resolve(message);
  }
}

// SQS队列实现
export class SqsQueueResolver implements QueueResolver {
  constructor(private readonly sqsService: SqsService) {}

  async send(queue: string, message: any): Promise<any> {
    return this.sqsService.send(queue, message);
  }
}

// 动态选择队列实现的工厂
export const QueueProvider = {
  provide: 'QueueResolver',
  useFactory: (
    configService: ConfigService,
    sqsOptions: SqsOptions,
    discoveryService: DiscoveryService,
  ) => {
    const env = configService.get<string>('NODE_ENV');
    if (env === 'development') {
      return new LocalQueueResolver();
    }
    // 生产环境用SQS,未来切换Cloud Tasks只需替换此处实例化逻辑
    const sqsService = new SqsService(sqsOptions, discoveryService);
    return new SqsQueueResolver(sqsService);
  },
  inject: [ConfigService, SQS_OPTIONS, DiscoveryService],
};

2. 修改CoreModule,导入SqsModule并导出QueueResolver

必须导入SqsModule来提供SQS_OPTIONS依赖,同时导出QueueResolver供其他模块使用:

// core.module.ts
import { Global, Module } from '@nestjs/common';
import { MailProvider } from 'core/mail/mail.provider';
import * as path from 'path';
import { MailerModule } from '@nestjs-modules/mailer';
import { ConfigService } from '@nestjs/config';
import { PugAdapter } from '@nestjs-modules/mailer/dist/adapters/pug.adapter';
import { QueueProvider } from './queue/queue.resolver';
import { SqsModule } from '@ssut/nestjs-sqs'; // 导入SqsModule

@Global()
@Module({
  imports: [
    MailerModule.forRootAsync({
      useFactory: async (configService: ConfigService) => ({
        transport: {
          host: configService.get('MAIL').host,
          secure: false,
          port: configService.get('MAIL').port,
          auth: {
            user: configService.get('MAIL').auth.user,
            pass: configService.get('MAIL').auth.pass,
          },
        },
        defaults: {
          from: `"${configService.get('MAIL').from.name}" <${configService.get('MAIL').from.email}>`,
        },
        template: {
          dir: path.join(__dirname, './mail/templates'),
          adapter: new PugAdapter(),
          options: {
            strict: true,
          },
        },
      }),
      inject: [ConfigService],
    }),
    // 导入并配置SqsModule,注册SQS_OPTIONS依赖
    SqsModule.forRootAsync({
      useFactory: async (configService: ConfigService) => ({
        consumers: [], // 根据业务需求配置消费者
        producers: [
          {
            name: configService.get('SQS.QUEUE_NAME'),
            queueUrl: configService.get('SQS.QUEUE_URL'),
            region: configService.get('SQS.REGION'),
          },
        ],
      }),
      inject: [ConfigService],
    }),
  ],
  providers: [MailProvider, QueueProvider],
  exports: [MailProvider, 'QueueResolver'], // 导出QueueResolver
})
export class CoreModule {}

3. 业务模块中使用QueueResolver

在需要发送队列消息的服务中,直接注入QueueResolver即可,无需关心底层实现:

// example.service.ts
import { Inject, Injectable } from '@nestjs/common';
import { QueueResolver } from 'core/queue/queue.resolver';

@Injectable()
export class ExampleService {
  constructor(@Inject('QueueResolver') private readonly queueResolver: QueueResolver) {}

  async sendQueueMessage() {
    await this.queueResolver.send('business-queue', { data: 'test content' });
  }
}
关键说明
  • SQS_OPTIONS是SqsModule内部注册的依赖,必须通过导入配置好的SqsModule,才能让Nest在模块上下文中找到该依赖,解决注入报错。
  • 通过环境变量动态切换队列实现,本地开发跳过队列直接处理,生产用SQS;未来切换Cloud Tasks时,只需新增CloudTasksQueueResolver类,修改工厂函数的实例化逻辑即可,完全符合解耦需求。

内容的提问来源于stack exchange,提问作者aasis504

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 14:25:26