Node.js DynamoDB javascript SDK batchWriteItem不';除非增加写入容量,否则无法完成
我正在运行一系列单元测试(node.js 4.x、aws sdk、mocha),在每次测试之前将数据加载到一个表中,然后在测试之后清除该表 我有两个测试失败,因为Node.js DynamoDB javascript SDK batchWriteItem不';除非增加写入容量,否则无法完成,node.js,mocha.js,amazon-dynamodb,Node.js,Mocha.js,Amazon Dynamodb,我正在运行一系列单元测试(node.js 4.x、aws sdk、mocha),在每次测试之前将数据加载到一个表中,然后在测试之后清除该表 我有两个测试失败,因为ConditionExpression触发了ConditionCheckFailedException。但如果我增加读/写容量,它们的测试就会通过 据我所知,SDK处理节流异常并为您重试,那么为什么我的测试不能运行得更慢并通过呢?相反,似乎测试未能完成扫描->batchWriteItem过程,因此当新测试开始时,表中仍保留有记录 团队成
ConditionExpression
触发了ConditionCheckFailedException
。但如果我增加读/写容量,它们的测试就会通过
据我所知,SDK处理节流异常并为您重试,那么为什么我的测试不能运行得更慢并通过呢?相反,似乎测试未能完成扫描
->batchWriteItem
过程,因此当新测试开始时,表中仍保留有记录
团队成员告诉我,他们也遇到过类似的问题,他们只是提高了吞吐量来解决问题。这不适合我。要么我做错了什么,我的测试存在竞争条件,要么应该有一个模式可以实现,以确保我的操作在被限制时完成?我应该能够使用节流指标来通知何时需要增加吞吐量,但我仍然能够继续重试,直到内存耗尽
还有其他人遇到过这个问题吗?你做了什么来处理这个问题呢?经过一些调试后,我注意到
UnprocessedItems
响应元素。在查找了未处理的ems
之后,我意识到我应该仔细阅读。下面的代码将以延迟(指数退避)运行重试循环:
var clearEventTable=函数(tableName,client,cleared){
var exclusiveStartKey=null;
var-retryCount=0;
var read=函数(查询、回调){
client.scan(查询,函数(错误,第页){
如果(错误){
控制台日志(err);
返回回调(err);
}
retryCount=0;
exclusiveStartKey=page.LastEvaluatedKey | | null;
如果(page.Count==0){
返回回调(null,{});
}
如果(page.Count<25&&exclusiveStartKey){
log(“已达到读取容量限制:”+JSON.stringify(第页,null,2));
}
var keys=\映射(page.Items,函数(n){
返回{DeleteRequest:{Key:n}};
});
变量批={
请求项:{},
ReturnConsumedCapacity:“索引”,
ReturnItemCollectionMetrics:“大小”
};
batch.RequestItems[tableName]=键;
回调(空,批处理);
});
};
var write=函数(批处理、回调){
if(批处理和批处理请求项){
client.batchWriteItem(批处理,函数(错误,结果){
如果(错误){
控制台日志(err);
返回回调(err);
}
if(Object.keys(result.UnprocessedItems).length!==0){
log(“重试batchWriteItem:+JSON.stringify(result,null,2));
retryCount++;
var重试={
RequestItems:result.UnprocessedItems,
ReturnConsumedCapacity:“索引”,
ReturnItemCollectionMetrics:“大小”
};
//使用指数退避重试
var delay=retryCount>0?(50*Math.pow(2,retryCount-1)):0;
setTimeout(写入(重试、回调)、延迟);
返回;
}
回调(null,result);
});
}否则{
回调(空);
}
};
变量参数={
TableName:TableName,
ProjectionExpression:“聚合id,id”,
限制:25,//每个batchWriteItem最多25个
一致阅读:错误,
ReturnConsumedCapacity:“总计”
};
async.doWhilst(函数(下一个){
//检索实体
if(排他性EStartKey)
params.ExclusiveStartKey=ExclusiveStartKey;
编写(写,读)(参数,函数(错误,结果){
如果(错误)下一个(错误);
else next(null,result);
});
},函数(){
//测试是否需要加载更多
返回exclusiveStartKey!==null;
},函数(err,r){
//返回结果
如果(错误){
控制台日志(err);
返回清除(错误);
}
返回清除(空);;
});
};
经过一些调试后,我注意到未处理的ems
响应元素。在查找了未处理的ems
之后,我意识到我应该仔细阅读。下面的代码将以延迟(指数退避)运行重试循环:
var clearEventTable=函数(tableName,client,cleared){
var exclusiveStartKey=null;
var-retryCount=0;
var read=函数(查询、回调){
client.scan(查询,函数(错误,第页){
如果(错误){
控制台日志(err);
返回回调(err);
}
retryCount=0;
exclusiveStartKey=page.LastEvaluatedKey | | null;
如果(page.Count==0){
返回回调(null,{});
}
如果(page.Count<25&&exclusiveStartKey){
log(“已达到读取容量限制:”+JSON.stringify(第页,null,2));
}
var keys=\映射(page.Items,函数(n){
返回{DeleteRequest:{Key:n}};
});
变量批={
请求项:{},
ReturnConsumedCapacity:“索引”,
ReturnItemCollectionMetrics:“大小”
};
batch.RequestItems[tableName]=键;
回调(空,批处理);
});
};
var write=函数(批处理、回调){
if(批处理和批处理请求项){
client.batchWriteItem(批处理,函数(错误,结果){
如果(错误){
控制台日志(err);
返回回调(err);
}
if(Object.keys(result.UnprocessedItems).length!==0){
log(“重试batchWriteItem:+JSON.stringify(result,null,2));
retryCount++;
var重试={
RequestItems:result.UnprocessedItems,
ReturnConsumedCapacity:“索引”,
ReturnItemCollectionMetrics:“大小”
};
//使用指数退避重试
var delay=retryCount>0?(50*数学功率(2,retr
var clearEventTable = function (tableName, client, cleared) {
var exclusiveStartKey = null;
var retryCount = 0;
var read = function(query, callback) {
client.scan(query, function (err, page) {
if(err) {
console.log(err);
return callback(err);
}
retryCount = 0;
exclusiveStartKey = page.LastEvaluatedKey || null;
if(page.Count == 0) {
return callback(null, {});
}
if(page.Count < 25 && exclusiveStartKey) {
console.log("read capacity limit reached: " + JSON.stringify(page, null, 2));
}
var keys = _.map(page.Items, function(n) {
return { DeleteRequest: { Key: n } };
});
var batch = {
RequestItems: {},
ReturnConsumedCapacity: "INDEXES",
ReturnItemCollectionMetrics: "SIZE"
};
batch.RequestItems[tableName] = keys;
callback(null, batch);
});
};
var write = function(batch, callback) {
if(batch && batch.RequestItems){
client.batchWriteItem(batch, function(err, result) {
if(err) {
console.log(err);
return callback(err);
}
if(Object.keys(result.UnprocessedItems).length !== 0) {
console.log("Retry batchWriteItem: " + JSON.stringify(result, null, 2));
retryCount++;
var retry = {
RequestItems: result.UnprocessedItems,
ReturnConsumedCapacity: "INDEXES",
ReturnItemCollectionMetrics: "SIZE"
};
// retry with exponential backoff
var delay = retryCount > 0 ? (50 * Math.pow(2, retryCount - 1)) : 0;
setTimeout(write(retry, callback), delay);
return;
}
callback(null, result);
});
} else {
callback(null);
}
};
var params = {
TableName: tableName,
ProjectionExpression: "aggregateId,id",
Limit: 25, // max 25 per batchWriteItem
ConsistentRead: false,
ReturnConsumedCapacity: "TOTAL"
};
async.doWhilst(function (next) {
// retrieve entities
if (exclusiveStartKey)
params.ExclusiveStartKey = exclusiveStartKey;
async.compose(write, read)(params, function (err, result) {
if (err) next(err);
else next(null, result);
});
}, function () {
// test if we need to load more
return exclusiveStartKey !== null;
}, function (err, r) {
// return results
if (err) {
console.log(err);
return cleared(err);
}
return cleared(null);;
});
};