Docker下Jest测试Mongoose Model查询超时但原生查询正常
故障概述
- 故障场景:Docker容器环境下运行Jest测试用例时突发Mongoose异常,应用与测试服务此前长期稳定运行
- 异常表现:Mongoose可正常建立MongoDB连接,执行原生驱动层面的集合查询
mongoose.connection.collection("users").findOne()可正常返回结果,但调用已注册的User模型方法(如User.findOne())时会持续阻塞,最终触发超时错误 - 复现差异:User模型在主应用中运行正常,相同环境配置下其他同事的个人电脑运行同一套测试用例无异常
- 已尝试无效操作:从零重建Docker镜像、执行
docker system prune清理环境、手动删除所有镜像与数据卷、多次清空~/.docker目录,均未解决问题
调试相关代码
测试用例代码
import mongoose from 'mongoose' import User from '../models/User.mjs'; describe('Debug', () => { test('test DB', async () => { await mongoose.connect("mongodb://mongo:27017/test", {}); console.log("Ready state: " + mongoose.connection.readyState); console.log(await mongoose.connection.collection("users").findOne()); console.log(User); console.log(await User.findOne()); await mongoose.disconnect(); }) })
User模型定义
import mongoose from 'mongoose' import bcrypt from 'mongoose-bcrypt' const UserSchema = new mongoose.Schema({ ...fields-omitted }, { timestamps: true }) export default mongoose.model('User', UserSchema);
运行报错输出
pptruser@b6cad840e3ca:/app$ npm test -- debug.test.js > debug-test@1.0.0 test > JEST_PUPPETEER_CONFIG=tests/jest-puppeteer.config.cjs node --experimental-vm-modules ./node_modules/.bin/jest --detectOpenHandles --runInBand "debug.test.js" (node:2647) ExperimentalWarning: VM Modules is an experimental feature. This feature could change at any time (Use `node --trace-warnings ...` to show where the warning was created) console.log Ready state: 1 at Object.<anonymous> (tests/debug.test.js:8:13) console.log { _id: new ObjectId("629dcc09a5c0753289a9e83a"), type: 'User', phoneNumber: '+1111111111', phoneNumberVerified: false, firstname: 'John', lastname: 'Doe', email: 'john.doe@test.at', username: '', provider: '', authToken: '', token: 'mDiQrWKFIPXO3VfvHbToAaEg', failedAuthCounter: 0, birthDate: 1950-01-01T00:00:00.000Z, rights: [], expireToken: 2022-06-06T09:42:33.155Z, createdAt: 2022-06-06T09:42:33.156Z, updatedAt: 2022-06-06T09:42:33.156Z, __v: 0 } at Object.<anonymous> (tests/debug.test.js:9:13) console.log Model { User } at Object.<anonymous> (tests/debug.test.js:10:13) FAIL tests/debug.test.js (5.59 s) Debug ✕ test DB (5001 ms) ● Debug › test DB thrown: "Exceeded timeout of 5000 ms for a test. Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test." 4 | describe('Debug', () => { 5 | > 6 | test('test DB', async () => { | ^ 7 | await mongoose.connect("mongodb://mongo:27017/test", {}); 8 | console.log("Ready state: " + mongoose.connection.readyState); 9 | console.log(await mongoose.connection.collection("users").findOne()); at tests/debug.test.js:6:3 at tests/debug.test.js:4:1 Test Suites: 1 failed, 1 total Tests: 1 failed, 1 total Snapshots: 0 total Time: 5.64 s, estimated 6 s Ran all test suites matching /debug.test.js/i
排查方向
- 优先排查
mongoose-bcrypt原生依赖兼容问题:原生驱动查询正常、模型查询阻塞,最高概率是Schema挂载的插件在执行阶段卡住。先注释掉User模型中mongoose-bcrypt的引入和注册,再跑测试用例,如果恢复正常,就是bcrypt原生模块和当前Docker环境的Node版本、CPU架构不兼容——这类原生C++扩展会在npm install时针对当前运行环境编译,跨架构(比如arm宿主机拉了x86镜像、或者镜像Node版本和编译时的版本不匹配)时不会直接抛启动错误,只会在实际调用哈希计算逻辑时死锁阻塞。 - 排查Mongoose模型重复注册问题:你启动测试时加了
--experimental-vm-modules参数,ESM模块和Jest的VM环境搭配时偶发会出现模块缓存失效,导致同一个Schema被重复注册到未建立连接的Mongoose实例上,模型和当前活跃连接不绑定,调用方法时会一直等待无响应。可以在调用User.findOne()前打印User.db === mongoose.connection验证是否为同一个连接实例,如果返回false,在connect之后先执行mongoose.deleteModel('User')重新注册模型即可验证。 - 排查全局钩子阻塞问题:检查是否有全局挂载的Mongoose pre钩子(比如
pre('find')/pre('init'))中存在未resolve的异步逻辑,或者钩子依赖的模块在测试环境加载异常导致执行卡住,可以给每个pre钩子加入口日志,确认执行卡在哪一步。
内容的提问来源于stack exchange,提问作者Somebody25
相关产品推荐
相关产品推荐

