今天下午修bug时发现的问题
如果在Nest中使用了官方的缓存模块(@nestjs/cache-manager
和cache-manager
),而且使用了Redis作为具体的缓存层实现,你可能会碰到配置看起来没什么问题(没有任何报错,同时Redis连接一切正常),但是Cache没有被正常写入Redis的情况
例如下面的配置:
CacheModule.registerAsync({
isGlobal: true,
imports: [ConfigModule],
inject: [HikariConfigService],
useFactory: async (configService: HikariConfigService) => {
const host = configService.get('redis.host')
const port = configService.get('redis.port')
const password = configService.get('redis.password')
const keyPrefix = configService.get('redis.keyPrefix')
const database = configService.get('redis.database')
return {
store: [
new KeyvAdapter(
await redisStore({
socket: { host, port },
password: password || undefined,
keyPrefix,
database,
}),
),
],
}
},
}),
实际上,上面的这段配置是几乎没有任何问题的,除了return对象中的stores
被错误地写为了store
- 迷惑点一:如果配置错误,包括但不限于拼写错误、没有使用Keyv作为adapter层等等,此时Nest并不会抛出任何错误来提醒你这里有问题
- 迷惑点二:就算配置错误,Redis也会正常连接。如果在return中正确初始化了redisStore,Redis实际上也会正常连上,如果你修改连接参数如host或者port,redisStore会因为连接不上Redis抛出异常,这会让你潜意识地认为上面的配置是没有问题的
- 迷惑点三:这是最难受的一点,如果CacheModule没有正确初始化redis实例,Nest会自动降级到使用内存作为缓存层,结果就是CACHE_MANAGER提供的所有方法,如
get
、set
、del
等,全部都看起来工作正常(实际上也确实工作正常,除了缓存数据存放的位置变成了内存而不是Redis),这会导致问题非常不容易被发现
弄清楚上面这几点后,相似的问题就很好解决了:
@nestjs/cache-manager
只会读取stores中的内容,确保stores
拼写无误,CacheModule会读取stores
数组中初始化的缓存实例,如果数组为空或者没有值,Nest会默认使用内存作为具体的缓存层stores
仅接受Keyv
实例或KeyvStoreAdapter
。如果没有使用Keyv作为adapter层,就算stores没拼错,redisStore正常初始化,配置也会失败
最后附上文档的配置示例,文档中使用了原生的keyv包作为adapter实现
import { Module } from '@nestjs/common';
import { CacheModule } from '@nestjs/cache-manager';
import { AppController } from './app.controller';
import { createKeyv } from '@keyv/redis';
import { Keyv } from 'keyv';
import { CacheableMemory } from 'cacheable';
@Module({
imports: [
CacheModule.registerAsync({
useFactory: async () => {
return {
stores: [
new Keyv({
store: new CacheableMemory({ ttl: 60000, lruSize: 5000 }),
}),
createKeyv('redis://localhost:6379'),
],
};
},
}),
],
controllers: [AppController],
})
export class AppModule {}
我们使用的,并且已经在生产环境中验证的相关依赖如下
import { CacheModule } from '@nestjs/cache-manager'
import { redisStore } from 'cache-manager-redis-yet'
import { KeyvAdapter } from 'cache-manager'
"@nestjs/cache-manager": "^3.0.1",
"cache-manager": "^6.4.3",
"cache-manager-redis-yet": "^5.1.5",
相关连接