Skip to content

Commit

Permalink
Use DependsOn to prevent API rate limits (#7)
Browse files Browse the repository at this point in the history
* Use DependsOn to prevent API rate limits

* Fix lint errors

* Update README.md
  • Loading branch information
sbstjn committed Jul 21, 2017
1 parent 2e023af commit dc5f75d
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 20 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ plugins:
- serverless-dynamodb-autoscaling
```
Configure DynamoDB Auto Scaling in `serverless.yml`:
Configure DynamoDB Auto Scaling in `serverless.yml` with references to your DynamoDB CloudFormation resources for the `table` property:

```yaml
custom:
capacities:
- name: custom-table # DynamoDB table name
- table: CustomTable # DynamoDB Resource
read:
minimum: 5 # Minimum read capacity
maximum: 1000 # Maximum read capacity
Expand All @@ -42,17 +42,19 @@ custom:
minimum: 40 # Minimum write capacity
maximum: 200 # Maximum write capacity
usage: 0.5 # Targeted usage percentage
- name: another-table
- table: AnotherTable
read:
minimum: 5
maximum: 1000
# usage: 0.75 is the default
```

That's it! With the next deployment (`sls deploy`) serverless will add a CloudFormation configuration to enable Auto Scaling for the DynamoDB tables `custom-table` and `another-table`.
That's it! With the next deployment (`sls deploy`) serverless will add a CloudFormation configuration to enable Auto Scaling for the DynamoDB resources `CustomTable` and `AnotherTable`.

You must of course provide at least a configuration for `read` or `write` to enable Auto Scaling. The value for `usage` has a default of 75 percent.

**Notice:** *With the relese of `v0.2.x` the plugin introduced a breaking change. Starting with `v0.2.0` you need to provide the CloudFormation reference for the `table` property. In `v0.1.x` the plugin used a `name` property with the DynamoDB table name.*

## DynamoDB

The configuration above works fine for a default DynamoDB table configuration.
Expand Down
4 changes: 4 additions & 0 deletions src/aws/policy.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ class Policy {
return {
[names.policyScale(this.table, this.read)]: {
'Type': 'AWS::ApplicationAutoScaling::ScalingPolicy',
'DependsOn': [
this.table,
names.target(this.table, this.read)
],
'Properties': {
'PolicyName': names.policyScale(this.table, this.read),
'PolicyType': 'TargetTrackingScaling',
Expand Down
5 changes: 4 additions & 1 deletion src/aws/role.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ class Role {
return {
[names.role(this.table)]: {
'Type': 'AWS::IAM::Role',
'DependsOn': [
this.table
],
'Properties': {
'RoleName': names.role(this.table),
'AssumeRolePolicyDocument': {
Expand Down Expand Up @@ -46,7 +49,7 @@ class Role {
'dynamodb:DescribeTable',
'dynamodb:UpdateTable'
],
'Resource': { 'Fn::Join': [ '', [ 'arn:aws:dynamodb:*:', { 'Ref': 'AWS::AccountId' }, ':table/' + this.table ] ] }
'Resource': { 'Fn::Join': [ '', [ 'arn:aws:dynamodb:*:', { 'Ref': 'AWS::AccountId' }, ':table/', { 'Ref': this.table } ] ] }
}
]
}
Expand Down
8 changes: 5 additions & 3 deletions src/aws/target.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
const util = require('util')
const names = require('./names')

class Target {
Expand All @@ -13,11 +12,14 @@ class Target {
return {
[names.target(this.table, this.read)]: {
'Type': 'AWS::ApplicationAutoScaling::ScalableTarget',
'DependsOn': names.role(this.table),
'DependsOn': [
this.table,
names.role(this.table)
],
'Properties': {
'MaxCapacity': this.max,
'MinCapacity': this.min,
'ResourceId': util.format('table/%s', this.table),
'ResourceId': { 'Fn::Join': [ '', [ 'table/', { 'Ref': this.table } ] ] },
'RoleARN': { 'Fn::GetAtt': [ names.role(this.table), 'Arn' ] },
'ScalableDimension': names.dimension(this.read),
'ServiceNamespace': 'dynamodb'
Expand Down
16 changes: 8 additions & 8 deletions src/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class Plugin {

defaults (config) {
return {
name: config.name,
table: config.table,
read: {
usage: config.read && config.read.usage ? config.read.usage : 0.75,
minimum: config.read && config.read.minimum ? config.read.minimum : 5,
Expand All @@ -48,7 +48,7 @@ class Plugin {
// Skip set if no read or write scaling configuration is available
if (!config.read && !config.write) {
return this.serverless.cli.log(
util.format(' - Skipping configuration for table "%s"', config.name)
util.format(' - Skipping configuration for resource "%s"', config.table)
)
}

Expand All @@ -58,25 +58,25 @@ class Plugin {

// Start processing configuration
this.serverless.cli.log(
util.format(' - Adding configuration for table "%s"', table.name)
util.format(' - Adding configuration for resource "%s"', table.table)
)

// Add role to manage Auto Scaling policies
resources.push(new Role(table.name))
resources.push(new Role(table.table))

// Only add Auto Scaling for read capacity if configuration set is available
if (config.read) {
resources.push(
new Policy(table.name, table.read.usage, true, 60, 60),
new Target(table.name, table.read.minimum, table.read.maximum, true)
new Policy(table.table, table.read.usage, true, 60, 60),
new Target(table.table, table.read.minimum, table.read.maximum, true)
)
}

// Only add Auto Scaling for write capacity if configuration set is available
if (config.write) {
resources.push(
new Policy(table.name, table.write.usage, false, 60, 60),
new Target(table.name, table.write.minimum, table.write.maximum, false)
new Policy(table.table, table.write.usage, false, 60, 60),
new Target(table.table, table.write.minimum, table.write.maximum, false)
)
}

Expand Down
4 changes: 0 additions & 4 deletions test/aws/target.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ describe('Target', () => {
const d = j[names.target('my-table-name', true)]

expect(d).toHaveProperty('Type', 'AWS::ApplicationAutoScaling::ScalableTarget')
expect(d).toHaveProperty('DependsOn', names.role('my-table-name'))
expect(d).toHaveProperty('Properties.MinCapacity', 4)
expect(d).toHaveProperty('Properties.MaxCapacity', 100)
expect(d).toHaveProperty('Properties.ResourceId', 'table/my-table-name')
expect(d).toHaveProperty('Properties.ScalableDimension', names.dimension(true))
expect(d).toHaveProperty('Properties.ServiceNamespace', 'dynamodb')
expect(d).toHaveProperty('Properties.RoleARN.Fn::GetAtt')
Expand All @@ -30,10 +28,8 @@ describe('Target', () => {
const d = j[names.target('my-table-name', false)]

expect(d).toHaveProperty('Type', 'AWS::ApplicationAutoScaling::ScalableTarget')
expect(d).toHaveProperty('DependsOn', names.role('my-table-name'))
expect(d).toHaveProperty('Properties.MinCapacity', 100)
expect(d).toHaveProperty('Properties.MaxCapacity', 2000)
expect(d).toHaveProperty('Properties.ResourceId', 'table/my-table-name')
expect(d).toHaveProperty('Properties.ScalableDimension', names.dimension(false))
expect(d).toHaveProperty('Properties.ServiceNamespace', 'dynamodb')
expect(d).toHaveProperty('Properties.RoleARN.Fn::GetAtt')
Expand Down

0 comments on commit dc5f75d

Please sign in to comment.