如何避免两个并发的API请求破坏文档验证背后的逻辑? [英] How to avoid two concurrent API requests breaking the logic behind document validation?

查看:48
本文介绍了如何避免两个并发的API请求破坏文档验证背后的逻辑?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个API,为了插入新项目,需要对其进行验证.验证基本上是类型验证器( string number Date 等),并查询数据库,以检查用户"是否具有相同日期的"item",如果验证成功,则失败.

I have an API that in order to insert a new item it needs to be validated. The validation basically is a type validator(string, number, Date, e.t.c) and queries the database that checks if the "user" has an "item" in the same date, which if it does the validation is unsuccessful.

伪代码是这样的:

const Item = require("./models/item");
function post(newDoc){

  let errors = await checkForDocErrors(newDoc)
  if (errors) {
    throw errors;
  }

  let itemCreated = await Item.create(newDoc);

  return itemCreated;


}

我的问题是,如果我同时执行两个并发请求:

My problem is if I do two concurrent requests like this:

const request = require("superagent");

// Inserts a new Item
request.post('http://127.0.0.1:5000/api/item')
.send({
  "id_user": "6c67ea36-5bfd-48ec-af62-cede984dff9d",
  "start_date": "2019-04-02",
  "name": "Water Bottle"
})
/* 
   Inserts a new Item, which shouldn't do. Resulting in two items having the
   same date.
*/
request.post('http://127.0.0.1:5000/api/item')
.send({
  "id_user": "6c67ea36-5bfd-48ec-af62-cede984dff9d",
  "start_date": "2019-04-02",
  "name": "Toothpick"
})


两者都将成功,这不应该成功,因为用户"在同一日期不能有两个项目".

Both will be successful, which it shouldn't be since an "user" cannot have two "items" in the same date.

如果我在第一个完成后执行了第二个,一切都会按预期进行.

If I execute the second one after the first is finished, everything works as expected.

request.post('http://127.0.0.1:5000/api/item') // Inserts a new Item
.send({
  "id_user": "6c67ea36-5bfd-48ec-af62-cede984dff9d",
  "start_date": "2019-04-02",
  "name": "Water Bottle"
})
.then((res) => {
  // It is not successful since there is already an item with that date
  // as expected
  request.post('http://127.0.0.1:5000/api/item') 
  .send({
    "id_user": "6c67ea36-5bfd-48ec-af62-cede984dff9d",
    "start_date": "2019-04-02",
    "name": "Toothpick"
  })
})

为避免这种情况,我发送了一个带有一系列文档的请求,但我想避免这一问题,或者至少避免发生这种情况.

To avoid this I send one request with an array of documents, but I want to prevent this issue or at least make less likely to happen.

解决方案

我创建了一个Redis服务器.使用软件包 redis-lock 并包裹在 POST 路线.

I created a redis server. Used the package redis-lock and wrapped around the POST route.

var client = require("redis").createClient()
var lock = require("redis-lock")(client);
var itemController = require('./controllers/item');
router.post('/', function(req, res){
  let userId = "";
  if (typeof req.body === 'object' && typeof req.body.id_user === 'string') {
    userId = req.body.id_user;
  }
  lock('POST ' + req.path + userId, async function(done){
    try {
      let result = await itemController.post(req.body)
      res.json(result);
    } catch (e) {
      res.status(500).send("Server Error");
    }
    done()

  })
}

谢谢.

推荐答案

解释

这是比赛条件.

两个或多个线程可以访问共享数据,并且它们尝试同时更改它们

two or more threads can access shared data and they try to change it at the same time

什么是比赛条件?

在这种情况下,有很多方法可以防止冲突数据,锁定是1选项.
您可以锁定应用程序级别或数据库级别...但是我希望您在选择其中任何一个之前先阅读此线程.

There are many ways to prevent conflict data in this case, a lock is 1 option.
You can lock on application level or database level... but I prefer you read this thread before chose any of them.

乐观锁定与悲观锁定
快速解决方案:悲观锁 https://www.npmjs.com/package/redis-lock

这篇关于如何避免两个并发的API请求破坏文档验证背后的逻辑?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆