node.js - 同步多个请求和多个数据库调用

标签 node.js mongodb asynchronous mongoose

我目前正在处理一个问题,当我在 Node.js 应用程序中的 mongo 数据库(使用 mongoose)中创建文档时,出现重复的键错误。

这是场景

更新特定用户的 HTTP 请求。

POST /process { "user": 123 }

服务器检查用户是否存在。如果不存在,则会创建一个新用户,否则会更新用户并保存。

User.findOne({ "user": 123 }, function (err, doc) {
    if (!doc) {
        doc = new User({ ... });
    }
    doc.updated = Date.now();
    doc.save(...);
}

有两个异步调用findOnesave。我面临的问题是,当在一个异步调用期间(即在第一个请求的 doc.save 完成之前)传入第二个 HTTP 请求(针对同一用户)时会发生什么情况。即使 Node.js 是单线程的,如果异步 I/O 期间存在一些延迟,这种情况仍然可能发生。

R1: POST /process
R1: findOne => async
R2: POST /process
R2: findOne => async
R1: !doc = true
R2: !doc = true

因此,对于这两个请求,应用程序都认为该用户不存在,因此尝试使用相同的 key 创建文档两次。

如何解决?

  • 首先,我最大限度地缩短了 findOnesave 之间的时间。然而,这个问题在某些情况下仍然会发生(可能只有 1/1000)。

  • 我不想使用 upsert,因为在创建新用户时我还设置了一些其他字段的默认值。我认为更新插入会很棘手。

  • 理想情况下,我想确保一次只有一个请求可以进入处理逻辑(有点像函数调用周围的互斥锁)。但是,我不想阻止请求调用 - 所以也许我可以使用一些不错的异步锁定实用程序?

示例:

/* don't block, call the function when a lock can be acquired */
lock(function (done) {
    /* can only enter here one at a time */
    done(); /* <-- unlocks */
}

或者,我是否以错误的方式处理这个问题。有什么想法吗?

最佳答案

简单。 不要直接使用.findOne().save(),而只是.update()数据库中的对象。

MongoDB 和“锁定”(以这种方式)不会发生,这基本上是设计使然。你不应该:

  1. 预订一本书
  2. 从书架上拿书
  3. 在书中写入新段落
  4. 将书放回书架
  5. 取消预订书籍供其他人使用

这是“可扩展模式中的一个巨大NO”。

所以而不是你只是这样做。

"Write new paragraph to book on shelf"

最好

"Write new paragraph to book on shelf, where the current paragraph is what I expect it to be".

这应该是一个“明确”的类比。

所以这样做:

User.update(
   { "user": 123 },
   { "$set": { "updated": new Date() } },
   function(err,numAffected) {
       // do something in callback
   }
);

这“简单”只是更新当时提出请求时的当前“更新”日期。

或者更好:

var updatedDate = new Date();

User.update(
   { "user": 123, "updated": { "$lt": updatedDate } },
   { "$set": { "updated": updatedDate } },
   function(err,numAffected) {
       // do something in callback
   }
);

不会触及对象的是“updated”的当前值“大于”您想要设置的值。

纯逻辑。

关于node.js - 同步多个请求和多个数据库调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31473123/

相关文章:

node.js - Node 模块别名错误 : Cannot find module '@src/utils/constants'

java - 如何考虑夏令时在 mongoDB 中存储 future 的调度日期

Mongodb 月周?

javascript - Mongoose 按数组最后一个对象中的属性分组

c# - 等到单元测试中的所有任务完成

javascript - Node.js:如何使用 proxyquire 替换 neo4j-driver 依赖

javascript - AWS Lambda Node Js JSON 未定义

node.js - Mongoose .save 函数似乎没有在 node.js 脚本中被调用

c# - 异步循环等待完成再继续

javascript - 如果执行时间太长,则跳过该功能。 JavaScript