You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在NestJS中如何借助cache-manager和cache-manager-redis-store实现Redis按匹配模式批量删除键?

在NestJS中如何借助cache-manager和cache-manager-redis-store实现Redis按匹配模式批量删除键?

我之前在NestJS项目里也碰到过一模一样的问题——cache-manager的上层封装确实把Redis的一些原生方法给藏起来了,一开始找底层客户端找得我头大。不过别担心,有几种靠谱的办法能实现按模式批量删键的需求,我给你慢慢说:

方法一:获取cache-manager封装的底层Redis客户端(推荐)

不同版本的cache-manager-redis-store对底层客户端的暴露方式略有不同,你之前试的this.cache.store.client或者this.cache.stores[0].client可能因为版本问题不生效,试试下面的方式:

步骤1:正确获取Redis客户端

在新版本的cache-manager-redis-store(比如v5及以上),底层客户端需要通过getClient()方法获取,老版本可能直接是store.client属性。你可以在你的服务里这么写:

const redisStore = this.cache.store as any;
const redisClient = redisStore.getClient(); // 老版本可以试试 redisStore.client

这里用as any是因为cache-manager的类型定义没有暴露这些底层方法,暂时绕过类型检查就行,后续也可以自己扩展类型定义来避免any。

步骤2:用SCAN命令遍历匹配的键(别用KEYS!)

千万不要用KEYS命令,它是阻塞式的,生产环境下如果Redis里键很多,会直接导致Redis卡顿甚至假死。一定要用SCAN命令迭代遍历匹配的键,然后批量删除:

import { Inject, Injectable } from '@nestjs/common';
import { Cache } from 'cache-manager';
import { CACHE_MANAGER } from '@nestjs/cache-manager';

@Injectable()
export class CacheService {
  constructor(@Inject(CACHE_MANAGER) private cache: Cache) {}

  async deleteKeysByPattern(pattern: string): Promise<number> {
    const redisStore = this.cache.store as any;
    const redisClient = redisStore.getClient();

    let cursor = '0';
    let totalDeleted = 0;

    do {
      // SCAN迭代:每次取100个匹配的键,可以根据实际情况调整COUNT参数
      const [nextCursor, matchedKeys] = await redisClient.scan(
        cursor,
        'MATCH',
        pattern,
        'COUNT',
        '100',
      );
      cursor = nextCursor;

      if (matchedKeys.length > 0) {
        // 用cache-manager的mdel批量删除
        await this.cache.mdel(...matchedKeys);
        totalDeleted += matchedKeys.length;
      }
    } while (cursor !== '0'); // 直到cursor回到0,说明遍历完成

    return totalDeleted;
  }
}

这样调用deleteKeysByPattern('user:*')就能删除所有以user:开头的键了。

方法二:单独引入Redis客户端实例

如果上面的方法因为版本兼容问题实在搞不定,你也可以单独安装ioredis或者官方的redis包,在NestJS里配置一个独立的Redis客户端provider,和cache-manager用完全相同的连接配置,这样就能直接调用原生的SCAN和DEL命令了。

比如用ioredis的话,先安装:

npm install ioredis

然后在NestJS里配置provider:

import { Module } from '@nestjs/common';
import Redis from 'ioredis';

@Module({
  providers: [
    {
      provide: 'REDIS_CLIENT',
      useFactory: () => {
        return new Redis({
          host: 'localhost', // 和cache-manager的配置一致
          port: 6379,
          password: 'your-redis-password',
        });
      },
    },
  ],
  exports: ['REDIS_CLIENT'],
})
export class RedisModule {}

之后在服务里注入使用,实现批量删除的逻辑和方法一类似,直接用原生客户端的scan和del/batch命令就行。

方法三:更换更友好的Redis存储适配器

如果上面两种方法都觉得麻烦,也可以考虑换成cache-manager-redis-yet这个包,它是cache-manager-redis-store的替代方案,API设计更清晰,更容易获取底层客户端,而且对NestJS的兼容性也很好。

最后提醒

  • 生产环境一定要用SCAN,别用KEYS!
  • 如果你用了类型断言as any,最好在项目里扩展cache-manager的类型定义,避免类型报错。

内容来源于stack exchange

火山引擎 最新活动