mongodb - MongoError:使用 NextJs api 时拓扑被破坏
问题描述
我正在使用 Vercel 无服务器功能为 Next.js 应用程序制作 API 端点。我正在使用 MongoDB 存储对象数组。
我有这个无服务器功能
// api/global/addlink.js
const MongoClient = require("mongodb").MongoClient;
const { ObjectId } = require("mongodb");
const client = new MongoClient(process.env.DB_URI, {});
export default async (req, res) => {
await client.connect();
const link = JSON.parse(req.body)["link"];
const query = { _id: ObjectId(JSON.parse(req.body)["_id"]) };
const result = await client
.db("myio_guests")
.collection("link_groups")
.findOneAndUpdate(query, {
$push: {
links: link,
},
});
res.json({
message: "link added successfully",
result: result,
});
await client.close();
};
此函数每运行 2 次就会出错。
我尝试了 4 次调用,该函数使用来自我的前端的 fetch post 请求,但只保存了 2 个条目,它们是第 1 个和第 3 个条目。在第 2 次和第 4 次调用的情况下,会发生此错误:
2021-01-26T14:14:18.964Z cae61486-ecb3-4726-aa8c-f8e95d9326ad WARN the options [servers] is not supported
2021-01-26T14:14:18.964Z cae61486-ecb3-4726-aa8c-f8e95d9326ad WARN the options [caseTranslate] is not supported
2021-01-26T14:14:18.964Z cae61486-ecb3-4726-aa8c-f8e95d9326ad WARN the options [dbName] is not supported
2021-01-26T14:14:18.964Z cae61486-ecb3-4726-aa8c-f8e95d9326ad WARN the options [srvHost] is not supported
2021-01-26T14:14:18.964Z cae61486-ecb3-4726-aa8c-f8e95d9326ad WARN the options [credentials] is not supported
2021-01-26T14:14:20.203Z cae61486-ecb3-4726-aa8c-f8e95d9326ad ERROR MongoError: topology was destroyed
at executeCommand (/var/task/node_modules/mongodb/lib/operations/db_ops.js:222:21)
at FindOneAndUpdateOperation.execute (/var/task/node_modules/mongodb/lib/operations/find_and_modify.js:107:5)
at executeOperation (/var/task/node_modules/mongodb/lib/operations/execute_operation.js:77:17)
at Collection.findOneAndUpdate (/var/task/node_modules/mongodb/lib/collection.js:1737:10)
at module.exports.lt9b.__webpack_exports__.default (/var/task/.next/serverless/pages/api/global/addlink.js:296:75)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async apiResolver (/var/task/node_modules/next/dist/next-server/server/api-utils.js:8:1)
at async /var/task/.next/serverless/pages/api/global/addlink.js:137:387
2021-01-26T14:14:20.203Z cae61486-ecb3-4726-aa8c-f8e95d9326ad ERROR MongoError: topology was destroyed
at executeCommand (/var/task/node_modules/mongodb/lib/operations/db_ops.js:222:21)
at FindOneAndUpdateOperation.execute (/var/task/node_modules/mongodb/lib/operations/find_and_modify.js:107:5)
at executeOperation (/var/task/node_modules/mongodb/lib/operations/execute_operation.js:77:17)
at Collection.findOneAndUpdate (/var/task/node_modules/mongodb/lib/collection.js:1737:10)
at module.exports.lt9b.__webpack_exports__.default (/var/task/.next/serverless/pages/api/global/addlink.js:296:75)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async apiResolver (/var/task/node_modules/next/dist/next-server/server/api-utils.js:8:1)
at async /var/task/.next/serverless/pages/api/global/addlink.js:137:387
2021-01-26T14:14:20.204Z cae61486-ecb3-4726-aa8c-f8e95d9326ad ERROR Unhandled Promise Rejection {"errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"MongoError: topology was destroyed","reason":{"errorType":"MongoError","errorMessage":"topology was destroyed","name":"MongoError","stack":["MongoError: topology was destroyed"," at executeCommand (/var/task/node_modules/mongodb/lib/operations/db_ops.js:222:21)"," at FindOneAndUpdateOperation.execute (/var/task/node_modules/mongodb/lib/operations/find_and_modify.js:107:5)"," at executeOperation (/var/task/node_modules/mongodb/lib/operations/execute_operation.js:77:17)"," at Collection.findOneAndUpdate (/var/task/node_modules/mongodb/lib/collection.js:1737:10)"," at module.exports.lt9b.__webpack_exports__.default (/var/task/.next/serverless/pages/api/global/addlink.js:296:75)"," at processTicksAndRejections (internal/process/task_queues.js:97:5)"," at async apiResolver (/var/task/node_modules/next/dist/next-server/server/api-utils.js:8:1)"," at async /var/task/.next/serverless/pages/api/global/addlink.js:137:387"]},"promise":{},"stack":["Runtime.UnhandledPromiseRejection: MongoError: topology was destroyed"," at process.<anonymous> (/var/runtime/index.js:35:15)"," at process.emit (events.js:326:22)"," at processPromiseRejections (internal/process/promises.js:209:33)"," at processTicksAndRejections (internal/process/task_queues.js:98:32)"]}
Unknown application error occurred
如何在这样的无服务器案例中解决此问题?
解决方案
您遇到的问题来自这一行:
await client.close();
从文档:
MongoClient.close() - 关闭底层连接器,进而关闭所有打开的连接。一旦调用,这个 Mongo 实例就不能再使用了。
这意味着当您close
成为客户端时,任何其他打开的连接也会关闭。在您的情况下,#2 和 #4 在 #1 和 #3 之后不久开始运行(但在它们完成之前),并且在它们仍在运行时关闭它们的连接。
同样来自文档:
MongoClient 类被设计为线程安全并在线程之间共享。通常,您只为给定的数据库集群创建 1 个实例并在您的应用程序中使用它。
最好的做法是为您的无状态函数(我知道)进行一些状态管理,拥有一个连接服务,只为您的无状态函数提供连接,这样管理错误也会更容易。
在此处和nodejs 驱动程序文档中阅读有关此内容的更多信息
解决您的问题的快速(并且非常次优)的解决方案是在函数中定义连接,如下所示:
// remove the definition from here
export default async (req, res) => {
// and move it here
const client = new MongoClient(process.env.DB_URI, {});
await client.connect();
.....
await client.close();
};
推荐阅读
- python - 我们如何在没有常数项的情况下使用 np.polyfit 来拟合多项式
- apache-spark - Spark 无法读取 avro 文件格式
- javascript - 如何通过更改一个列号字段来更新另一个列号字段
- google-apps-script - 使用谷歌应用脚本的动态依赖下拉列表不起作用 - Google 表格
- r - 从 API 请求中提取 json 内容时出错:错误:解析错误:过早的 EOF?
- c - 我无法在 C 中操作位域
- powerbi - 带有最后值的 3 个月滚动平均值
- spring-batch - 在 AsyncItemProcessor 中设置上下文参数
- ios - 应用程序进入后台后,AVAudioPlayer 停止返回正确的 currentTime
- php - “getimagesize(): SSL operation failed with code 1” 仅在本地 Xampp