diff --git a/.github/workflows/deploy-examples.yml b/.github/workflows/deploy-examples.yml index f9337289..080a05a6 100644 --- a/.github/workflows/deploy-examples.yml +++ b/.github/workflows/deploy-examples.yml @@ -73,8 +73,8 @@ jobs: - name: Deploy Lambda function - ${{ matrix.example.name }} env: AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} - LAMBDA_ENDPOINT: ${{ secrets.LAMBDA_ENDPOINT }} - INVOKE_ACCOUNT_ID: ${{ secrets.INVOKE_ACCOUNT_ID }} + LAMBDA_ENDPOINT: ${{ secrets.LAMBDA_ENDPOINT_BETA }} + INVOKE_ACCOUNT_ID: ${{ secrets.INVOKE_ACCOUNT_ID_BETA }} KMS_KEY_ARN: ${{ secrets.KMS_KEY_ARN }} run: | # Build function name @@ -98,7 +98,7 @@ jobs: - name: Invoke Lambda function - ${{ matrix.example.name }} env: - LAMBDA_ENDPOINT: ${{ secrets.LAMBDA_ENDPOINT }} + LAMBDA_ENDPOINT: ${{ secrets.LAMBDA_ENDPOINT_BETA }} run: | echo "Testing qualified function: $QUALIFIED_FUNCTION_NAME" aws lambda invoke \ @@ -139,7 +139,7 @@ jobs: - name: Find Durable Execution - ${{ matrix.example.name }} env: - LAMBDA_ENDPOINT: ${{ secrets.LAMBDA_ENDPOINT }} + LAMBDA_ENDPOINT: ${{ secrets.LAMBDA_ENDPOINT_BETA }} run: | echo "Listing durable executions for qualified function: $QUALIFIED_FUNCTION_NAME" aws lambda list-durable-executions-by-function \ @@ -159,7 +159,7 @@ jobs: - name: Get Durable Execution History - ${{ matrix.example.name }} if: env.EXECUTION_ARN != '' env: - LAMBDA_ENDPOINT: ${{ secrets.LAMBDA_ENDPOINT }} + LAMBDA_ENDPOINT: ${{ secrets.LAMBDA_ENDPOINT_BETA }} run: | echo "Getting execution history for: $EXECUTION_ARN" aws lambda get-durable-execution-history \ @@ -174,7 +174,7 @@ jobs: # - name: Cleanup Lambda function # if: always() # env: - # LAMBDA_ENDPOINT: ${{ secrets.LAMBDA_ENDPOINT }} + # LAMBDA_ENDPOINT: ${{ secrets.LAMBDA_ENDPOINT_BETA }} # run: | # echo "Deleting function: $FUNCTION_NAME" # aws lambda delete-function \ diff --git a/examples/cli.py b/examples/cli.py index ab41663c..322fa05a 100755 --- a/examples/cli.py +++ b/examples/cli.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 import argparse -import contextlib import json import logging import os import shutil import sys +import time import zipfile from pathlib import Path @@ -321,6 +321,30 @@ def get_lambda_client(): ) +def retry_on_resource_conflict(func, *args, max_retries=5, **kwargs): + """Retry function on ResourceConflictException.""" + for attempt in range(max_retries): + try: + return func(*args, **kwargs) + except Exception as e: + if ( + hasattr(e, "response") + and e.response.get("Error", {}).get("Code") + == "ResourceConflictException" + and attempt < max_retries - 1 + ): + wait_time = 2**attempt # Exponential backoff + logger.info( + "ResourceConflictException on attempt %d, retrying in %ds...", + attempt + 1, + wait_time, + ) + time.sleep(wait_time) + continue + raise + return None + + def deploy_function(example_name: str, function_name: str | None = None): """Deploy function to AWS Lambda.""" catalog = load_catalog() @@ -370,17 +394,21 @@ def deploy_function(example_name: str, function_name: str | None = None): try: lambda_client.get_function(FunctionName=function_name) - lambda_client.update_function_code( - FunctionName=function_name, ZipFile=zip_content + retry_on_resource_conflict( + lambda_client.update_function_code, + FunctionName=function_name, + ZipFile=zip_content, + ) + retry_on_resource_conflict( + lambda_client.update_function_configuration, **function_config ) - lambda_client.update_function_configuration(**function_config) except lambda_client.exceptions.ResourceNotFoundException: lambda_client.create_function(**function_config, Code={"ZipFile": zip_content}) # Update invoke permission for worker account using put_resource_policy function_arn = f"arn:aws:lambda:{config['region']}:{config['account_id']}:function:{function_name}" - + policy_document = { "Version": "2012-10-17", "Statement": [ @@ -389,14 +417,13 @@ def deploy_function(example_name: str, function_name: str | None = None): "Effect": "Allow", "Principal": {"AWS": config["invoke_account_id"]}, "Action": "lambda:InvokeFunction", - "Resource": f"{function_arn}:*" + "Resource": f"{function_arn}:*", } - ] + ], } lambda_client.put_resource_policy( - ResourceArn=function_arn, - Policy=json.dumps(policy_document) + ResourceArn=function_arn, Policy=json.dumps(policy_document) ) logger.info("Function deployed successfully! %s", function_name)