Express API测试遇Jest进程终止/段错误问题求助
Express API Jest测试Redis连接导致SIGSEGV问题解决
问题现象
- 基于Express开发的API,使用Jest+Supertest做接口测试时,仅在VSCode打开状态下运行测试会触发SIGSEGV错误,外部终端运行测试全部正常
- 核心报错信息:
FAIL src/modules/ingredients/tests/updateingredient.test.ts ● Test suite failed to run A jest worker process (pid=672269) was terminated by another process: signal=SIGSEGV, exitCode=null. Operating system logs may contain more information on why this occurred. at ChildProcessWorker._onExit (node_modules/jest-worker/build/workers/ChildProcessWorker.js:366:23) (node:672290) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 open listeners added to [_0x323dee]. Use emitter.setMaxListeners() to increase limit (Use `node --trace-warnings ...` to show where the warning was created)
- 用
--detectOpenHandles排查:VSCode环境下输出Segmentation fault (core dumped),外部终端显示Redis连接的TCPWRAP未正确关闭
已尝试无效的方案
- 在Jest的
afterAll钩子中使用多种方式关闭Redis连接(直接调用redis.quit()、监听end事件等待连接关闭) - 重装VSCode、Node.js,更换多个Node版本
- 执行
npm rebuild、卸载VSCode Jest扩展、删除node_modules后重装全部依赖
根本原因
Redis单例在测试套件间共享,每个测试文件导入时都会直接创建连接,且测试结束后未彻底销毁实例,导致连接泄漏;VSCode环境下Jest的worker进程管理机制加剧了连接竞争,触发内存访问错误(SIGSEGV)。
解决方案
1. 将Redis单例改为延迟初始化
避免模块加载时立即创建连接,改为按需获取实例,同时提供清理方法:
// src/utils/redis.ts import Redis from 'ioredis'; import config from 'config'; import { Logger } from 'src/logger/logger'; const redisDb = config.get<number>('redis_db'); let redisInstance: Redis | null = null; export const getRedis = () => { if (!redisInstance) { redisInstance = new Redis({ port: 6379, host: '127.0.0.1', db: redisDb, }); redisInstance.on('ready', () => Logger.info('redis ready')); redisInstance.on('error', (error) => { Logger.error(`error with redis connection: ${error}`); redisInstance?.disconnect(); }); } return redisInstance; }; // 用于测试时销毁实例 export const closeRedis = async () => { if (redisInstance) { await redisInstance.quit(); redisInstance = null; } };
2. 全局测试钩子统一管理Redis连接
在Jest配置中添加全局初始化文件,统一处理测试后的连接清理:
// jest.config.js module.exports = { // 其他原有配置 setupFilesAfterEnv: ['<rootDir>/src/test/setup.ts'], };
// src/test/setup.ts import { closeRedis } from '../utils/redis'; afterAll(async () => { await closeRedis(); });
3. 替换所有Redis实例引用
将项目中所有直接导入redis的地方,改为调用getRedis()获取实例:
// 示例:ingredients.controller.ts import { getRedis } from 'src/utils/redis'; // 使用Redis时 const redis = getRedis(); await redis.setex(`ingredients_allergen_${parsedNames}`, 3600, JSON.stringify(foundIngredients));
4. 调整Jest配置减少进程冲突
在jest.config.js中添加以下配置,避免多worker进程的连接竞争:
module.exports = { // 其他原有配置 maxWorkers: 1, // 单worker运行测试 detectOpenHandles: true, };
验证结果
- VSCode打开状态下运行所有测试,无SIGSEGV错误和内存泄漏警告
- 再次执行
--detectOpenHandles检测,无未关闭的TCPWRAP连接
内容的提问来源于stack exchange,提问作者Oscar Sanz
相关产品推荐
相关产品推荐

