Create, update and delete handlers must answer within 60 seconds with a progress event: IN_PROGRESS, SUCCESS or FAILED. A slow operation returns IN_PROGRESS with a callback context, and CloudFormation 24 calls again with it until success, failure or the schema's timeoutInMinutes (default 120; 720 for tables). Read returns the live model or NotFound; list returns every identifier. LocalStack 63,725 's providers follow the same contract in Python; this is 4.13.1's table delete handler, from services/dynamodb/resource_providers/aws_dynamodb_table.py in the container:
model = request.desired_state
if not request.custom_context.get(REPEATED_INVOCATION):
request.custom_context[REPEATED_INVOCATION] = True
request.aws_client_factory.dynamodb.delete_table(TableName=model["TableName"])
return ProgressEvent(status=OperationStatus.IN_PROGRESS, ...)
try:
table_state = request.aws_client_factory.dynamodb.describe_table(
TableName=model["TableName"]
)
match table_state["Table"]["TableStatus"]:
case "DELETING":
return ProgressEvent(status=OperationStatus.IN_PROGRESS, ...)
case invalid_state:
return ProgressEvent(status=OperationStatus.FAILED, ...)
except request.aws_client_factory.dynamodb.exceptions.TableNotFoundException:
return ProgressEvent(status=OperationStatus.SUCCESS, resource_model={})The first call starts the deletion and marks the context; later calls only poll, and "not found" means success. Providers you write with the CloudFormation CLI 338 (github.com/aws-cloudformation/cloudformation-cli (https://github.com/aws-cloudformation/cloudformation-cli 338 ), pip 21,050 install cloudformation-cli plus a Java, Go, Python or TypeScript plugin) work the same way, and cfn test runs the contract tests they must pass.