NestJS多Worker线程启动微服务时Provider类互相覆盖问题问询
问题原因
你之所以使用worker线程仍未实现作用域隔离,核心是两点:
- 你在bootstrap文件顶部写了三个服务的静态导入语句,JS的静态导入会在当前脚本加载阶段就全部执行,不管后续会不会用到对应的导出内容。也就是说不管是主进程启动,还是每个worker线程启动,只要加载这个bootstrap文件,都会先把serviceA、serviceB、serviceC三个服务的所有依赖代码全加载一遍,触发所有服务的provider注册逻辑。
- 你用的DI框架(从
@Module装饰器判断为NestJS)的同token provider默认是后注册覆盖先注册的逻辑,三个服务都给CARD_PROVIDER_FACADE_FACTORY这个token注册了实现,最后加载的服务的实现自然会覆盖之前的,注入的时候拿到的永远是最后注册的那个。
解决方案
你目前用的动态import按需加载是最优的解决方案,调整步骤如下:
- 首先删除bootstrap文件顶部的三个服务静态导入:
// 删掉以下三行 // import { serviceA } from '@company/serviceA' // import { serviceB } from '@company/serviceB' // import { serviceC } from '@company/serviceC'
- 在
childService方法的对应分支里按需动态导入对应的服务:
async childService({ service }: WorkerData) { console.log(`Starting Service - ${service}`) switch (service) { case Services.serviceA: const { serviceA } = await import('@company/serviceA') return await serviceA() case Services.serviceB: const { serviceB } = await import('@company/serviceB') return await serviceB() case Services.serviceC: const { serviceC } = await import('@company/serviceC') return await serviceC() default: throw new Error('Service Unavailable'); } }
这个方案的优势是:
- 无需修改公共模块或者DI注册逻辑,改造成本极低
- 每个worker线程只会加载自己需要的服务代码,不会加载另外两个服务的依赖,内存占用更低
- 从根源上避免了不同服务的provider同时注册导致的覆盖问题
如果不想用动态导入,也可以拆分启动入口:给每个服务单独写一个启动脚本,每个脚本只导入自己需要的服务,创建worker的时候指定对应服务的启动脚本即可,不过这个方案会增加入口文件的维护成本。
内容的提问来源于stack exchange,提问作者Mylo Warden
相关产品推荐
相关产品推荐

