Skip to content

Commit e7fd506

Browse files
authored
fix: Check if DynamoDB table exists before create (#5658)
1 parent da6257c commit e7fd506

1 file changed

Lines changed: 47 additions & 19 deletions

File tree

‎sdk/python/feast/infra/online_stores/dynamodb.py‎

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -203,26 +203,45 @@ def update(
203203
kwargs = {"Tags": table_tags} if table_tags else {}
204204

205205
table_name = _get_table_name(online_config, config, table_instance)
206+
# Check if table already exists before attempting to create
207+
# This is required for environments where IAM roles don't have
208+
# dynamodb:CreateTable permissions (e.g., Terraform-managed tables)
209+
table_exists = False
206210
try:
207-
dynamodb_resource.create_table(
208-
TableName=table_name,
209-
KeySchema=[{"AttributeName": "entity_id", "KeyType": "HASH"}],
210-
AttributeDefinitions=[
211-
{"AttributeName": "entity_id", "AttributeType": "S"}
212-
],
213-
BillingMode="PAY_PER_REQUEST",
214-
**kwargs,
211+
dynamodb_client.describe_table(TableName=table_name)
212+
table_exists = True
213+
do_tag_updates[table_name] = True
214+
logger.info(
215+
f"DynamoDB table {table_name} already exists, skipping creation"
215216
)
216-
217217
except ClientError as ce:
218-
do_tag_updates[table_name] = True
219-
220-
# If the table creation fails with ResourceInUseException,
221-
# it means the table already exists or is being created.
222-
# Otherwise, re-raise the exception
223-
if ce.response["Error"]["Code"] != "ResourceInUseException":
218+
if ce.response["Error"]["Code"] != "ResourceNotFoundException":
219+
# If it's not a "table not found" error, re-raise
224220
raise
225221

222+
# Only attempt to create table if it doesn't exist
223+
if not table_exists:
224+
try:
225+
dynamodb_resource.create_table(
226+
TableName=table_name,
227+
KeySchema=[{"AttributeName": "entity_id", "KeyType": "HASH"}],
228+
AttributeDefinitions=[
229+
{"AttributeName": "entity_id", "AttributeType": "S"}
230+
],
231+
BillingMode="PAY_PER_REQUEST",
232+
**kwargs,
233+
)
234+
logger.info(f"Created DynamoDB table {table_name}")
235+
236+
except ClientError as ce:
237+
do_tag_updates[table_name] = True
238+
239+
# If the table creation fails with ResourceInUseException,
240+
# it means the table already exists or is being created.
241+
# Otherwise, re-raise the exception
242+
if ce.response["Error"]["Code"] != "ResourceInUseException":
243+
raise
244+
226245
for table_instance in tables_to_keep:
227246
table_name = _get_table_name(online_config, config, table_instance)
228247
dynamodb_client.get_waiter("table_exists").wait(TableName=table_name)
@@ -712,13 +731,22 @@ def _delete_table_idempotent(
712731
table.delete()
713732
logger.info(f"Dynamo table {table_name} was deleted")
714733
except ClientError as ce:
734+
error_code = ce.response["Error"]["Code"]
735+
715736
# If the table deletion fails with ResourceNotFoundException,
716737
# it means the table has already been deleted.
717-
# Otherwise, re-raise the exception
718-
if ce.response["Error"]["Code"] != "ResourceNotFoundException":
719-
raise
720-
else:
738+
if error_code == "ResourceNotFoundException":
721739
logger.warning(f"Trying to delete table that doesn't exist: {table_name}")
740+
# If it fails with AccessDeniedException, the IAM role doesn't have
741+
# dynamodb:DeleteTable permission (e.g., Terraform-managed tables)
742+
elif error_code == "AccessDeniedException":
743+
logger.warning(
744+
f"Unable to delete table {table_name} due to insufficient permissions. "
745+
f"The table may need to be deleted manually or via your infrastructure management tool (e.g., Terraform)."
746+
)
747+
else:
748+
# Some other error, re-raise
749+
raise
722750

723751

724752
def _to_resource_write_item(config, entity_key, features, timestamp):

0 commit comments

Comments
 (0)