1

I'd like to "truncate" (delete all items) in a DynamoDB table. I know that the most efficient way to do this would be to delete the table and re-create it (name, indexes, etc.). However, the table is part of a SAM-CloudFormation deployment. The table (by name) is also referenced within other parts of the application.

If I deleted and re-created it, I could use the same name it had previously; however, I think this would cause problems because (1) the deletion isn't immediate and (2) the ARN would change and that could have implications on the CloudFormation stack.

It seems that there should be a better solution than the brute-force approach: iterate through all items, deleting them one at a time (with some optimization via the batch_writer).

I've looked at some other solutions here, but they don't address the "part of a CloudFormation stack" part of my question.

I even provided a brute-force solution myself to another's question on this topic.

Here is the brute force approach

import boto3

table = boto3.resource('dynamodb').Table('my-table-name')
scan = None

with table.batch_writer() as batch:
    count = 0
    while scan is None or 'LastEvaluatedKey' in scan:
        if scan is not None and 'LastEvaluatedKey' in scan:
            scan = table.scan(
                ProjectionExpression='id',
                ExclusiveStartKey=scan['LastEvaluatedKey'],
            )
        else:
            scan = table.scan(ProjectionExpression='id')

        for item in scan['Items']:
            if count % 5000 == 0:
                print(count)
            batch.delete_item(Key={'id': item['id']})
            count = count + 1

The desired final state is a DynamoDB table (that was previously full of items) with the same name, no items, and still able to be destroyed as part of a CloudFormation delete operation.

Matt
  • 907
  • 1
  • 8
  • 17
  • Make sure you scan consistently with `ConsistentRead: True`, otherwise you may get the same items repeatedly if you scan fast enough after a batch write delete. – Renato Byrro Jul 30 '19 at 23:26

1 Answers1

3

No matter if you created the table as AWS::Serverless::SimpleTable or AWS::DynamoDB::Table there is no out-of-the-box solution to empty it using CloudFormation while keeping its name.

As a general best practice you shouldn't name DynamoDB tables created by CloudFormation, but let CloudFormation assign a name for the resource. If that would have been the case in your setup you could simply do a change to the resource which requires "replacement" of the resource, like temporary adding a Local Secondary Index, which would recreate the resource and would work with resources depending on it.

That said, in your situation the best approach is probably be to wrap your brute force approach in a CloudFormation custom resource and include that in your CloudFormation stack. With that you can truncate the table once or, depending on the implementation of your custom resource, whenever you want.

Keep in mind that deleting all items from a DynamoDB table might take quite long, so using a Lambda-backed custom resource might run into the limit of Lambda function runtime, depending on the number of items in the table. It might also become quite costly if the table contains a lot of items.

Dunedan
  • 7,848
  • 6
  • 42
  • 52
  • I think the idea to force a "truncate" by doing two changes to the template is really interesting. ¿Is something like this what you're thinking/suggesting? (regarding the "replacement" option). Use [boto's stack update](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudformation.html#CloudFormation.Stack.update) to make a change that forces replacement (ex. change the [table's key schema](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-table.html#cfn-dynamodb-table-keyschema)) and then change it back to the way it was. – Matt Jun 17 '19 at 17:22
  • Yes, that's the idea. That doesn't work though if you rely on a manually set name for the table (as you do according to your question), as that'd result in CloudFormation trying to replace a resource identified by one ARN with another resource identified by the same ARN (as CloudFormation creates the new resource before deleting the old one (see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html for reference)). – Dunedan Jun 18 '19 at 03:39
  • Got it. Thanks so much. I want using the name when creating it but I see where I've written that. I was thinking of dynamically getting the name (as set by CF) right before delete and then creating a table with that same name via API. If the arn is based on the table name, might this work? – Matt Jun 19 '19 at 02:37
  • Sorry. I meant "I WASN'T using a name when creating..." – Matt Jun 19 '19 at 04:48