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

如何在NestJS中使用Cache Manager配置Redis缓存自动超时失效

实现NestJS Cache Manager缓存自动过期(30秒)

问题描述

我正在开发一个提供天气API的NestJS项目,使用NestJS Cache Manager而非原生Redis驱动。目前缓存中的数据会永久存储,希望配置Redis和/或Cache Manager,使存储超过30秒的缓存数据自动失效。

当前代码实现

Cache模块(AppCacheModule)

import { Module } from '@nestjs/common';
import { CacheModule } from '@nestjs/cache-manager';
import { RedisOptions } from './config/redis.config';

@Module({
  imports: [CacheModule.registerAsync(RedisOptions)]
})
export class AppCacheModule {}

Redis配置(RedisOptions)

import { CacheModuleAsyncOptions } from '@nestjs/cache-manager';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { redisStore } from 'cache-manager-redis-store';

export const RedisOptions: CacheModuleAsyncOptions = {
  isGlobal: true,
  imports: [ConfigModule],
  useFactory: async (configService: ConfigService) => {
    const store = await redisStore({
      socket: {
        host: configService.get<string>('REDIS_HOST'),
        port: parseInt(configService.get<string>('REDIS_PORT'))
      }
    });
    return {
      store: () => store
    };
  },
  inject: [ConfigService]
};

天气服务(WeatherService)

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

import { FullWeatherData } from 'src/weather/api/types';
import { WeatherApiService } from 'src/weather/provider/weather.provider.interface';

/**
 * Service handling weather-related business logic.
 *
 * @class
 */
@Injectable()
export class WeatherService {
  /**
   * Creates an instance of WeatherService.
   *
   * @constructor
   * @param {WeatherApiService} weatherApi - An instance of the weather API provider.
   *   Injected based on the configured provider token.
   */
  constructor(
    @Inject('WeatherApiService') private weatherApi: WeatherApiService,
    @Inject(CACHE_MANAGER) private cacheManager: Cache
  ) {}

  /**
   * Retrieves weather data by latitude and longitude.
   *
   * @public
   * @async
   * @param {number} lat - The latitude coordinate.
   * @param {number} lon - The longitude coordinate.
   * @returns {Promise<FullWeatherData>} A promise that resolves to the retrieved weather data.
   */
  public async getWeatherData(lat: number, lon: number): Promise<FullWeatherData> {
    const cacheKey = this.getCacheKey(lat, lon);
    const cachedData = await this.cacheManager.get<FullWeatherData | undefined>(
      cacheKey
    );

    if (cachedData) {
      return cachedData;
    }

    const data: FullWeatherData = await this.weatherApi.getWeatherData(lat, lon);
    this.cacheManager.set(cacheKey, data);

    return data;
  }

  /**
   * Constructs a cache key based on provided latitude and longitude.
   *
   * @param {number} lat – Latitude.
   * @param {number} lon – Longitude.
   * @returns {string} Cache key.
   */
  private getCacheKey(lat: number, lon: number): string {
    return `${lat}:${lon}`;
  }
}

解决方案

有两种方式可以实现缓存自动失效,可根据需求选择:

方式一:全局配置默认TTL(推荐)

在Redis配置中添加全局默认的过期时间(TTL,单位:秒),这样所有缓存键都会自动应用这个过期时间。

修改RedisOptions的useFactory返回值,添加ttl: 30:

import { CacheModuleAsyncOptions } from '@nestjs/cache-manager';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { redisStore } from 'cache-manager-redis-store';

export const RedisOptions: CacheModuleAsyncOptions = {
  isGlobal: true,
  imports: [ConfigModule],
  useFactory: async (configService: ConfigService) => {
    const store = await redisStore({
      socket: {
        host: configService.get<string>('REDIS_HOST'),
        port: parseInt(configService.get<string>('REDIS_PORT'))
      }
    });
    return {
      store: () => store,
      ttl: 30 // 全局默认缓存过期时间:30秒
    };
  },
  inject: [ConfigService]
};

方式二:单个缓存键指定TTL

如果只需要特定缓存键设置过期时间,可以在调用cacheManager.set时传入TTL参数:

修改WeatherService中的getWeatherData方法,在set方法中添加ttl选项:

public async getWeatherData(lat: number, lon: number): Promise<FullWeatherData> {
  const cacheKey = this.getCacheKey(lat, lon);
  const cachedData = await this.cacheManager.get<FullWeatherData | undefined>(
    cacheKey
  );

  if (cachedData) {
    return cachedData;
  }

  const data: FullWeatherData = await this.weatherApi.getWeatherData(lat, lon);
  // 设置缓存并指定30秒后过期
  await this.cacheManager.set(cacheKey, data, { ttl: 30 });

  return data;
}

注意:这里要加上await确保缓存设置完成,避免异步操作导致的潜在问题。

两种方式可以结合使用:全局设置默认TTL,特定缓存键可以通过传入不同的TTL值覆盖全局配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 18:52:49