Sails-Mongo 2.0添加第15个集合时报Callback was already called错误
问题描述
添加第15个数据集合时,Waterline ORM启动失败,抛出Callback was already called.错误,错误详情如下:
Error: Callback was already called.
错误调用栈:at eval (webpack://mnUvr-api/./node_modules/async/dist/async.js?:843:36) at eval (webpack://mnUvr-api/./node_modules/waterline/lib/waterline/utils/system/validate-datastore-connectivity.js?:31:14) at eval (webpack://mnUvr-api/./node_modules/machine/lib/private/help-build-machine.js?:952:35) at Function.handlerCbs.error (webpack://mnUvr-api/./node_modules/machine/lib/private/help-build-machine.js?:742:26) at parley.retry (webpack://mnUvr-api/./node_modules/machine/lib/private/help-build-machine.js?:1088:49) at parley (webpack://mnUvr-api/./node_modules/parley/lib/parley.js?:140:5) at Object.runFn [as getConnection] (webpack://mnUvr-api/./node_modules/machine/lib/private/help-build-machine.js?:461:23) at validateDatastoreConnectivity (webpack://mnUvr-api/./node_modules/waterline/lib/waterline/utils/system/validate-datastore-connectivity.js?:27:25) at eval (webpack://mnUvr-api/./node_modules/waterline/lib/waterline.js?:722:18) at Object.success (webpack://mnUvr-api/./node_modules/sails-mongo/lib/index.js?:356:16) at eval (webpack://mnUvr-api/./node_modules/machine/lib/private/help-build-machine.js?:1517:30) at proceedToFinalAfterExecLC (webpack://mnUvr-api/./node_modules/parley/lib/private/Deferred.js?:1155:14) at proceedToInterceptsAndChecks (webpack://mnUvr-api/./node_modules/parley/lib/private/Deferred.js?:913:12) at proceedToAfterExecSpinlocks (webpack://mnUvr-api/./node_modules/parley/lib/private/Deferred.js?:845:10) at eval (webpack://mnUvr-api/./node_modules/parley/lib/private/Deferred.js?:303:7) at eval (webpack://mnUvr-api/./node_modules/machine/lib/private/help-build-machine.js?:954:24)
已知复现条件:
- 集合数量达到15个时稳定触发,暂未在空白项目做复现验证
- 使用默认无定制的数据库连接配置,Sails-Mongo版本为2.0
- 前14个集合可正常加载使用,新增第15个集合时触发错误
- 已排除模型本身问题:移除新增模型所有属性、确认无语法错误后,错误仍然存在
相关数据库初始化代码如下:
export const connectToDatabase = (): Promise<void> => { if (orm) { return Promise.resolve(); } return new Promise((resolve, reject) => { Waterline.start(config, (err: unknown, _orm: Waterline.Waterline) => { if (err) { console.error("Could not start up the ORM:\n", err); return reject(err); } orm = _orm as Waterline; collections = { Syllabus: getModel("syllabus"), Clazz: getModel("clazz"), Move: getModel("move"), User: getModel<UserModel>("user"), Family: getModel("family"), Video: getModel("video"), ClazzLevel: getModel<ClazzModel>("clazzlevel"), ClazzMembership: getModel("clazzmembership"), syllabusOwnership: getModel("syllabusownership"), series: getModel("series"), SchoolOwnership: getModel("schoolownership"), School: getModel("school"), Product: getModel("product"), StudentProgress: getModel("studentprogress"), seriesMembership: getModel("seriesMembership"), }; resolve(); }); }); };
根因说明
该问题是Sails-Mongo 2.0.0版本的已知缺陷:启动阶段的datastore连通性校验逻辑未做回调幂等处理,当集合数量较多时,初始化阶段的连接重试逻辑会和首次连接结果逻辑同时触发,导致同一个回调被重复调用,抛出对应错误。和模型定义本身没有关系,15个集合是触发该bug的常见并发阈值。
修复方案
按优先级从高到低选择即可:
- 升级sails-mongo到2.1.0及以上稳定版本,官方已经在新版本中修复了该校验逻辑的回调重复调用问题,是成本最低、最稳妥的修复方式
- 若暂时无法升级依赖,可在Waterline启动配置中添加validateDatastoreConnectivity: false配置项,跳过存在缺陷的启动连通性校验逻辑。注意关闭该配置后需要自行保证数据库连接参数正确,可在ORM启动后加一条简单的数据查询操作做连通性探测
- 若既不能升级依赖也不想关闭校验,可在MongoDB连接串中添加参数maxPoolSize=20(设置为大于等于当前集合总数的值即可),避免初始化阶段连接池资源不足触发重试逻辑,规避回调重复调用的问题
以上方案任意一种生效后,重启服务即可正常加载全部集合,不会再抛出该错误。
内容的提问来源于stack exchange,提问作者Sean
相关产品推荐
相关产品推荐

