NestJS中Redis缓存失效时禁用缓存避免服务崩溃
NestJS Redis缓存容错方案(Redis宕机时服务正常运行)
一、修改CacheModule配置:连接失败自动降级
将同步注册改为异步注册,在工厂函数中捕获Redis初始化错误,降级到内存缓存或直接禁用缓存:
import { CacheModule, Module } from "@nestjs/common"; import * as redisStore from "cache-manager-redis-store"; import { memoryStore } from "cache-manager"; // 若要完全禁用缓存,需先执行 npm install cache-manager-noop-store // import { noopStore } from "cache-manager-noop-store"; @Module({ imports: [ CacheModule.registerAsync({ isGlobal: true, useFactory: async () => { try { return { store: redisStore, host: process.env.REDIS_HOST, port: process.env.REDIS_PORT, password: process.env.REDIS_ACCESS_KEY, tls: { host: process.env.REDIS_HOST }, ttl: 1800, }; } catch (err) { console.warn("Redis连接失败,切换到内存缓存", err.message); // 若要完全禁用缓存,替换为 store: noopStore return { store: memoryStore, ttl: 1800 }; } }, }), ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
二、自定义容错拦截器:避免CacheInterceptor报错
默认CacheInterceptor在Redis故障时会抛出错误导致请求失败,自定义拦截器捕获错误后直接执行原请求逻辑:
import { CacheInterceptor, ExecutionContext, Injectable } from "@nestjs/common"; import { Observable, catchError } from "rxjs"; @Injectable() export class FaultTolerantCacheInterceptor extends CacheInterceptor { intercept(context: ExecutionContext, call$: Observable<any>): Observable<any> { return super.intercept(context, call$).pipe( catchError((err) => { console.warn("缓存拦截器操作失败,跳过缓存", err.message); return call$; }) ); } }
替换控制器中的拦截器:
import { Controller, Get, UseInterceptors } from "@nestjs/common"; import { FaultTolerantCacheInterceptor } from "./fault-tolerant-cache.interceptor"; @Controller() @UseInterceptors(FaultTolerantCacheInterceptor) export class AppController { @Get() findAll(): string[] { return []; } }
三、封装cache.wrap:捕获缓存操作错误
直接使用cacheManager.wrap会在Redis故障时抛出错误,封装工具方法兜底业务逻辑:
创建缓存服务:
import { Inject, Injectable } from "@nestjs/common"; import { CACHE_MANAGER, Cache } from "cache-manager"; @Injectable() export class CacheService { constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {} async wrap<T>(key: string, fallback: () => Promise<T>): Promise<T> { try { return await this.cacheManager.wrap(key, fallback); } catch (err) { console.warn(`缓存key [${key}]操作失败,直接调用业务逻辑`, err.message); return fallback(); } } }
控制器中使用封装后的服务(修正原代码中code笔误为id):
import { Body, Controller, Post } from "@nestjs/common"; import { ItemsService } from "./items.service"; import { CacheService } from "./cache.service"; @Controller("items") export class ItemsController { constructor( private itemsService: ItemsService, private cacheService: CacheService ) {} @Post("id") async getItemById(@Body("id") id: number) { return this.cacheService.wrap(`item-${id}`, () => this.itemsService.getItem(id) ); } }
内容的提问来源于stack exchange,提问作者Yahli Gitzi
相关产品推荐
相关产品推荐

