除非我增加写入容量,否则DynamoDB javascript SDK batchWriteItem不会完成

时间:2016-08-03 22:37:36

标签: node.js mocha amazon-dynamodb

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

我有两个失败的测试,因为ConditionExpression会触发ConditionCheckFailedException。但如果我增加读/写容量,他们就会通过测试。

我的理解是SDK处理限制异常并为您重试它们,为什么我的测试不会运行得更慢并且通过?相反,似乎测试无法完成scan - > batchWriteItem进程,因此当新测试开始时,表中仍有记录。

我被团队成员告知他们已经看到类似的问题,他们只是增加了解决问题的吞吐量。这不适合我。要么我做错了,我的测试有竞争条件,或者我应该有一个模式可以确保我的操作在受到限制时完成?我应该能够使用限制指标来告知何时需要增加吞吐量,但是我仍然可以继续重试,直到内存不足为止。

是否还有其他人遇到过此问题以及您采取了哪些措施来处理此问题?

2 个答案:

答案 0 :(得分:1)

经过一些调试后,我注意到了UnprocessedItems响应元素。在查找UnprocessedItems in the docs之后,我意识到我应该更仔细地阅读。下面的代码将运行一个带延迟的重试循环(指数退避):

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);;
  });
};

答案 1 :(得分:0)

还要查看为Lambda设置的内存量。可能太低了,达到最大值会导致IMX无法预测的结果。