Node.js DynamoDB javascript SDK batchWriteItem不';除非增加写入容量,否则无法完成

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过程,因此当新测试开始时,表中仍保留有记录 团队成

我正在运行一系列单元测试(node.js 4.x、aws sdk、mocha),在每次测试之前将数据加载到一个表中,然后在测试之后清除该表

我有两个测试失败,因为
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);;
  });
};