Reputation: 716
I just created a global module to work with Redis. At first it just provided the client:
// redis.module.ts
import { Global, Module } from '@nestjs/common'
import { createClient } from 'redis'
import { RedisMutex } from './redis-mutex.service'
export const REDIS = 'redis'
@Global()
@Module({
providers: [
{
provide: REDIS,
useFactory: async () => {
const client = createClient()
await client.connect()
return client
},
},
],
exports: [REDIS],
})
export class RedisModule {}
It worked well, I could inject it everywhere with no issue at all. Next, I created a class to implement mutex with this client under the same module:
// redis-mutex.service.ts
import { Inject, Injectable } from '@nestjs/common'
import { randomBytes } from 'crypto'
import { RedisClientType } from 'redis'
import { REDIS } from './redis.module'
@Injectable()
export class RedisMutex {
constructor(@Inject(REDIS) private redis: RedisClientType) {}
async lock(lockName: string): Promise<() => void> {
// ...code
}
}
Add it as a provider to the module and export:
// redis.module.ts
import { Global, Module } from '@nestjs/common'
import { createClient } from 'redis'
import { RedisMutex } from './redis-mutex.service'
export const REDIS = 'redis'
@Global()
@Module({
providers: [
{
provide: REDIS,
useFactory: async () => {
const client = createClient()
await client.connect()
return client
},
},
RedisMutex,
],
exports: [REDIS, RedisMutex],
})
export class RedisModule {}
Everything's still fine. Then I injected RedisMutex into 2 other providers in outside modules. Those other modules don't explicitly import RedisModule and they don't inject REDIS, only RedisMutex. RedisModule is only added to the imports of AppModule.
At this point Nest starts reporting a circular dependency, but without its trace:
Error: A circular dependency has been detected. Please, make sure that each side of a bidirectional relationships are decorated with "forwardRef()".
at NestContainer.addProvider (/home/andrey/Code/cashflowio/node_modules/@nestjs/core/injector/container.js:107:19)
at DependenciesScanner.insertProvider (/home/andrey/Code/cashflowio/node_modules/@nestjs/core/scanner.js:201:35)
at /home/andrey/Code/cashflowio/node_modules/@nestjs/core/scanner.js:105:18
at Array.forEach (<anonymous>)
at DependenciesScanner.reflectProviders (/home/andrey/Code/cashflowio/node_modules/@nestjs/core/scanner.js:104:19)
at DependenciesScanner.scanModulesForDependencies (/home/andrey/Code/cashflowio/node_modules/@nestjs/core/scanner.js:85:18)
at DependenciesScanner.scan (/home/andrey/Code/cashflowio/node_modules/@nestjs/core/scanner.js:29:9)
at /home/andrey/Code/cashflowio/node_modules/@nestjs/core/nest-factory.js:95:17
at Function.asyncRun (/home/andrey/Code/cashflowio/node_modules/@nestjs/core/errors/exceptions-zone.js:22:13)
at NestFactoryStatic.initialize (/home/andrey/Code/cashflowio/node_modules/@nestjs/core/nest-factory.js:94:13)
So I don't know what's causing it. I went as far as to wrap every single new injection that I just wrote in forwardRef, but that didn't help. How do I find out what dependencies is Nest referencing here?
Upvotes: 0
Views: 710
Reputation: 70460
I would bet this is actually referring to your REDIS
token and the RedisMutex
provider, as they are cyclically dependent via their files (the module file imports the provider the provider file import the module file). You should move the REDIS
constant token to it's own redis.constants.ts
file to ensure this doesn't happen.
Side note: circular dependencies are hard to report and document because the provider token that's read is undefined
. I might look into improving the parent provider was being read from, if that's possible, but generally at the moment it's pretty much easiest to just say "Hey there's something cyclic here and I don't know how to deal with it"
Upvotes: 1