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

如何让NestJS应用在Redis未运行时仍能正常启动

实现NestJS在Redis未启动时正常启动的方案

问题现状

  • Redis正常运行时,NestJS应用启动正常;
  • 应用运行中Redis宕机,已配置的事件监听可自动重试重连;
  • 启动NestJS前Redis已宕机,应用会因Redis连接失败直接启动失败,报错connect ECONNREFUSED。

问题根源

在RedisOptions的useFactory中直接await redisStore()创建Redis存储时,若Redis不可达,该调用会直接抛出错误,导致CacheModule初始化失败,进而阻断整个NestJS应用的启动流程。

解决方案

核心思路是:将Redis客户端的初始化与应用启动流程解耦,避免连接失败直接阻断模块初始化,同时保留自动重连逻辑。具体修改如下:

1. 修改Redis配置,手动控制客户端连接时机

修改redis.config.ts中的RedisOptions,先创建Redis客户端并关闭自动连接,再手动触发连接(连接失败不阻断存储创建),最后将客户端传入redisStore:

import { CACHE_MANAGER, CacheModuleAsyncOptions } from '@nestjs/cache-manager';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { RedisStore, redisStore } from 'cache-manager-redis-store';
import { Inject, Logger, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { Cache } from 'cache-manager';
import { CacheService } from '../services/cache.service';
import { createClient } from '@redis/client';

export const RedisOptions: CacheModuleAsyncOptions = {
  isGlobal: true,
  imports: [ConfigModule],
  useFactory: async (configService: ConfigService) => {
    // 创建Redis客户端,关闭自动连接
    const client = createClient({
      socket: {
        host: configService.get<string>('API_REDIS_HOST'),
        port: parseInt(configService.get<string>('API_REDIS_PORT')!),
        connectTimeout: 3000,
        reconnectStrategy(retries: number): number | Error {
          if (retries > 39) {
            console.log('Redis - 达到最大重连次数');
            return new Error('Max retries reached');
          }
          return 3000;
        },
        tls: process.env.NODE_ENV !== 'local',
        rejectUnauthorized: false,
      },
      autoConnect: false, // 禁用自动连接,避免初始化时抛出错误
    });

    // 手动触发连接,连接失败仅打印日志,不阻断流程
    client.connect().catch(err => {
      console.error('Redis初始连接失败,将自动重试:', err);
    });

    // 使用已创建的客户端创建redisStore
    const store = await redisStore({
      client: client,
    });

    return {
      store: () => store,
    };
  },
  inject: [ConfigService],
};

2. 优化Redis事件监听逻辑

调整RedisClientEventListener,适配客户端延迟连接的场景,确保事件监听正常生效:

export class RedisClientEventListener implements OnModuleInit, OnModuleDestroy {
  private readonly logger = new Logger(RedisClientEventListener.name);
  private readonly redisStore: RedisStore;

  constructor(@Inject(CACHE_MANAGER) readonly cacheManager: Cache) {
    this.redisStore = cacheManager.store as unknown as RedisStore;
  }

  onModuleInit(): void {
    console.log("AppModule启动中...")
    const client = this.redisStore.getClient();

    if (!client) {
      this.logger.error('Redis客户端未初始化');
      CacheService.isHealthy = false;
      return;
    }

    // 初始状态判断
    CacheService.isHealthy = client.isReady;
    if (client.isReady) {
      this.logger.log('Redis客户端已连接就绪');
    } else {
      this.logger.log('Redis客户端待连接,将自动重试');
    }

    // 绑定各类事件监听
    client.on('connect', () => {
      this.logger.log('Redis客户端正在连接服务器...');
    });

    client.on('ready', () => {
      this.logger.log('Redis客户端连接就绪');
      CacheService.isHealthy = true;
    });

    client.on('end', () => {
      this.logger.log('Redis客户端连接已关闭');
      CacheService.isHealthy = false;
    });

    client.on('error', (error: Error) => {
      this.logger.error(error, 'Redis客户端发生错误');
      CacheService.isHealthy = false;
    });
  }

  async onModuleDestroy(): Promise<void> {
    const client = this.redisStore.getClient();
    // 根据客户端状态选择关闭方式
    if (client.isReady) {
      await client.quit();
    } else {
      await client.disconnect();
    }
  }
}

3. 保留应用启动错误容忍配置

确保main.ts中的abortOnError: false配置生效,避免其他非致命错误阻断启动:

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    abortOnError: false,
  });

  await app.listen(3000);
}

bootstrap();

验证效果

启动NestJS前关闭Redis,此时应用会正常启动,控制台打印Redis初始连接失败,将自动重试,之后Redis客户端会按照配置的策略自动重试连接。当Redis启动后,客户端会触发ready事件,CacheService.isHealthy会自动切换为true,应用可正常使用Redis缓存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 22:08:15