Search code examples
javascriptnode.jsamazon-dynamodbaws-sdkaws-sdk-js

How to enable Auto Scaling for Provisioned read capacity in DynamoDB from java script


I am using AWS SDK for nodejs and creating a dynamodb table from the code. It all works fine but i need auto scaling to be enabled for provisioned read and write capacity. This is the code i am trying

var params = {
    TableName : "MyTable",
    KeySchema: [       
        { AttributeName: "Name", KeyType: "HASH"},  //Partition key
        { AttributeName: "time", KeyType: "RANGE" }  //Sort key
    ],
    AttributeDefinitions: [     

        { AttributeName: "Name", AttributeType: "S" },
        { AttributeName: "time", AttributeType: "N" }
    ],
    ProvisionedThroughput: {       
        ReadCapacityUnits: 5, 
        WriteCapacityUnits: 5
    }        
    ]
};

dynamodb.createTable(params, function(err, data) {
    if (err) {
        console.error("Unable to create table. Error JSON:", JSON.stringify(err, null, 2));
    } else {
        console.log("Created table. Table description JSON:", JSON.stringify(data, null, 2));
    }
});

This creates a table with read and write capacity as 5 but with auto scaling disabled. I have seen a java sample where auto scaling is being handled from code but nothing for java script. Any suggestions on how to enable auto scaling from NodeJS will be very helpful . Thanks


Solution

  • I followed jens walters solution and the UI for dynamodb looked broken--from overview it said scaling was enabled but when I viewed the capacity tab it didn't show that it was. This is because that solution is missing the second half--scaling policy.

    The solution is a 2 step process:

    1. Register the scalable target
    2. Put the scaling policy in place on the target

    Here's the code:

    var tableName = "your-table-name"
    
    var autoscalingParams = {
       MaxCapacity: 15,
       MinCapacity: 1,
       ResourceId: "table/" + tableName,
       RoleARN: "arn:aws:iam::" + accountId + ":role/current-lambdaRole",
       ScalableDimension: "dynamodb:table:WriteCapacityUnits",
       ServiceNamespace: "dynamodb"
    };
    
    autoscaling.registerScalableTarget(autoscalingParams, function(err, data) {
       if(err) {
           console.log('error');
           console.log(JSON.stringify(err));
       } else {
           console.log(data);
       }
    
       var scalingPolicy = {
           ServiceNamespace: "dynamodb",
           ResourceId: "table/" + tableName,
           ScalableDimension: "dynamodb:table:WriteCapacityUnits",
           PolicyName: tableName + "-scaling-policy",
           PolicyType: "TargetTrackingScaling",
           TargetTrackingScalingPolicyConfiguration: {
               PredefinedMetricSpecification: {
                   PredefinedMetricType: "DynamoDBWriteCapacityUtilization"
               },
               ScaleOutCooldown: 60,
               ScaleInCooldown: 60,
               TargetValue: 70.0
           }
       };
    
       autoscaling.putScalingPolicy(scalingPolicy, function(err, data) {
           if(err) {
               console.log('error');
               console.log(JSON.stringify(err));
           } else {
               console.log('success!');
               console.log(data);
           }
           cb(err);
       });
    });
    

    Then your role will need permissions something along the lines of:

    {
      "IamPolicyLambdaManageScalingDynamoDbTables": {
        "Type": "AWS::IAM::Policy",
        "Properties": {
          "PolicyName": "someName",
          "PolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
              {
                "Effect": "Allow",
                "Action": [
                  "application-autoscaling:RegisterScalableTarget",
                  "application-autoscaling:PutScalingPolicy",
                  "iam:CreateServiceLinkedRole",
                  "iam:PassRole"
                ],
                "Resource": "*"
              }
            ]
          },
          "Roles": [
            {
              "Ref": "IamRoleLambdaExecution"
            }
          ]
        }
      }
    }
    

    Note: You should probably not use the wildcard for the role resource, but I haven't nailed down what those should be exactly