11#!/usr/bin/env python3
22
33import argparse
4- import contextlib
54import json
65import logging
76import os
87import shutil
98import sys
9+ import time
1010import zipfile
1111from pathlib import Path
1212
@@ -321,6 +321,30 @@ def get_lambda_client():
321321 )
322322
323323
324+ def retry_on_resource_conflict (func , * args , max_retries = 5 , ** kwargs ):
325+ """Retry function on ResourceConflictException."""
326+ for attempt in range (max_retries ):
327+ try :
328+ return func (* args , ** kwargs )
329+ except Exception as e :
330+ if (
331+ hasattr (e , "response" )
332+ and e .response .get ("Error" , {}).get ("Code" )
333+ == "ResourceConflictException"
334+ and attempt < max_retries - 1
335+ ):
336+ wait_time = 2 ** attempt # Exponential backoff
337+ logger .info (
338+ "ResourceConflictException on attempt %d, retrying in %ds..." ,
339+ attempt + 1 ,
340+ wait_time ,
341+ )
342+ time .sleep (wait_time )
343+ continue
344+ raise
345+ return None
346+
347+
324348def deploy_function (example_name : str , function_name : str | None = None ):
325349 """Deploy function to AWS Lambda."""
326350 catalog = load_catalog ()
@@ -370,17 +394,21 @@ def deploy_function(example_name: str, function_name: str | None = None):
370394
371395 try :
372396 lambda_client .get_function (FunctionName = function_name )
373- lambda_client .update_function_code (
374- FunctionName = function_name , ZipFile = zip_content
397+ retry_on_resource_conflict (
398+ lambda_client .update_function_code ,
399+ FunctionName = function_name ,
400+ ZipFile = zip_content ,
401+ )
402+ retry_on_resource_conflict (
403+ lambda_client .update_function_configuration , ** function_config
375404 )
376- lambda_client .update_function_configuration (** function_config )
377405
378406 except lambda_client .exceptions .ResourceNotFoundException :
379407 lambda_client .create_function (** function_config , Code = {"ZipFile" : zip_content })
380408
381409 # Update invoke permission for worker account using put_resource_policy
382410 function_arn = f"arn:aws:lambda:{ config ['region' ]} :{ config ['account_id' ]} :function:{ function_name } "
383-
411+
384412 policy_document = {
385413 "Version" : "2012-10-17" ,
386414 "Statement" : [
@@ -389,14 +417,13 @@ def deploy_function(example_name: str, function_name: str | None = None):
389417 "Effect" : "Allow" ,
390418 "Principal" : {"AWS" : config ["invoke_account_id" ]},
391419 "Action" : "lambda:InvokeFunction" ,
392- "Resource" : f"{ function_arn } :*"
420+ "Resource" : f"{ function_arn } :*" ,
393421 }
394- ]
422+ ],
395423 }
396424
397425 lambda_client .put_resource_policy (
398- ResourceArn = function_arn ,
399- Policy = json .dumps (policy_document )
426+ ResourceArn = function_arn , Policy = json .dumps (policy_document )
400427 )
401428
402429 logger .info ("Function deployed successfully! %s" , function_name )
0 commit comments