使用 nodejs 防止竞争条件

preventing race conditions with nodejs

我正在使用 nodeJS 6.3.0 和 aws DynamoDB 编写应用程序。

dynamodb 保存添加到 dynamodb 的统计信息,这些信息被从 10 个不同的函数(10 个不同的统计度量)调用。间隔设置为 10 秒,这意味着每 10 秒,将对我的函数进行 10 次调用以添加所有相关信息。

putItem 函数:

function putItem(tableName,itemData,callback) {
var params = {
    TableName: tableName,
    Item: itemData
};
docClient.put(params, function(err, data) {
    if (err) {
        logger.error(params,"putItem failed in dynamodb");
        callback(err,null);
    } else {
        callback(null,data);
    }
});

现在...我创建了一个队列。

var queue = require('./dynamoDbQueue').queue;

它实现了我从 http://www.bennadel.com/blog/2308-creating-a-fixed-length-queue-in-javascript-using-arrays.htm.

获取的固定大小的简单队列

想法是,如果出现网络问题.. 让我们等一下。我希望将所有事件推送到队列中,并在问题解决后将队列信息发送到 dynamodb 并释放队列。

所以我将我原来的函数修改为如下代码:

function putItem(tableName,itemData,callback) {
var params = {
    TableName: tableName,
    Item: itemData
};
if (queue.length>0) {
    queue.push(params);
    callback(null,null);
} else {
    docClient.put(params, function (err, data) {
        if (err) {
            queue.push(params);
            logger.error(params, "putItem failed in dynamodb");
            handleErroredQueue(); // imaginary function that i need to implement
            callback(err, null);
        } else {
            callback(null, data);
        }
    });
}
}

但是因为我有 10 个同时运行的插入函数,所以有可能出现竞争条件。这意味着...

execute1 - 一个函数验证队列为空...并且即将执行 docClient.put() 函数。

execute2 - 同时另一个函数从 docClient.put() 返回错误,结果它添加到队列的第一行。

execute1 - 当第一个函数调用 docClient.put() 时,问题已经解决,它成功地将数据插入到 dynamodb,这使得队列中包含将在下一次迭代中释放的先前数据。

例如,如果我插入 4 行 ID 为 1,2,3,4,将插入到 dynamodb 的行的顺序是 1,2,4,3

有办法解决吗?

谢谢!

我认为您的方向是正确的,但我建议的不是检查错误然后将其添加到队列中,而是先将每个操作添加到队列中,然后每次都从队列中读取数据。

例如,在您的情况下,您调用了函数 1,2,3,4,结果为 1,2,4,3,因为您在关闭 error/abrupt 操作时使用了队列。

Step1: All your function will make an entry to a Queue -> 1,2,3,4
Step2: Read your queue and make an insert, if success remove the element
       else redo the operation. This way it will insert in the desired sequence

另一个优点是,因为您正在使用队列,所以您不必为 table.

保持非常高的吞吐量。

编辑:

我想您只需要确保在完成第一个操作后执行下一个过程,而不是在此之前。

例如:fn 1 -> 从队列中读取(不要立即从队列中删除) -> 如果不再执行则操作完成 -> 从队列中删除 -> 执行下一个操作。

您只需确保从队列中读取并等待您收到 DynamoDB 的响应。

希望对您有所帮助。