使用nodejs防止竞争条件

时间:2016-07-17 13:08:12

标签: node.js queue amazon-dynamodb race-condition

我正在使用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中,这使得队列具有将在下一次迭代中释放的先前数据。

因此,例如,如果我插入带有1,2,3,4的4行,则将插入到dynamodb的行的顺序为1,2,4,3

有办法解决这个问题吗?

谢谢!

1 个答案:

答案 0 :(得分:2)

我认为你处于正确的轨道,但我没有检查错误然后添加到队列中,我建议先将每个操作添加到队列中,然后每次都从队列中读取数据。

例如,在您的情况下,您调用函数1,2,3,4并导致1,2,4,3,因为您在错误/突然操作时一直使用队列。

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

另一个优点是,因为您正在使用队列,所以不必为表保持非常高的吞吐量。

修改

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

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

您必须确保从队列中读取并等待您从DynamoDB获得响应。

希望这有帮助。