|
9 | 9 | DurableExecutionInvocationInputWithClient, |
10 | 10 | DurableExecutionInvocationOutput, |
11 | 11 | InitialExecutionState, |
| 12 | + InvocationStatus, |
12 | 13 | ) |
13 | 14 |
|
14 | 15 | from aws_durable_execution_sdk_python_testing.exceptions import ( |
15 | 16 | DurableFunctionsTestError, |
16 | 17 | ) |
17 | 18 | from aws_durable_execution_sdk_python_testing.model import LambdaContext |
18 | 19 |
|
19 | | - |
20 | 20 | if TYPE_CHECKING: |
21 | 21 | from collections.abc import Callable |
22 | 22 |
|
@@ -143,17 +143,107 @@ def invoke( |
143 | 143 | function_name: str, |
144 | 144 | input: DurableExecutionInvocationInput, |
145 | 145 | ) -> DurableExecutionInvocationOutput: |
146 | | - # TODO: wrap ResourceNotFoundException from lambda in ResourceNotFoundException from this lib |
147 | | - response = self.lambda_client.invoke( |
148 | | - FunctionName=function_name, |
149 | | - InvocationType="RequestResponse", # Synchronous invocation |
150 | | - Payload=json.dumps(input.to_dict(), default=str), |
| 146 | + """Invoke AWS Lambda function and return durable execution result. |
| 147 | +
|
| 148 | + Args: |
| 149 | + function_name: Name of the Lambda function to invoke |
| 150 | + input: Durable execution invocation input |
| 151 | +
|
| 152 | + Returns: |
| 153 | + DurableExecutionInvocationOutput: Result of the function execution |
| 154 | +
|
| 155 | + Raises: |
| 156 | + ResourceNotFoundException: If function does not exist |
| 157 | + InvalidParameterValueException: If parameters are invalid |
| 158 | + DurableFunctionsTestError: For other invocation failures |
| 159 | + """ |
| 160 | + from aws_durable_execution_sdk_python_testing.exceptions import ( |
| 161 | + ResourceNotFoundException, |
| 162 | + InvalidParameterValueException, |
151 | 163 | ) |
152 | 164 |
|
153 | | - # very simplified placeholder lol |
154 | | - if response["StatusCode"] == 200: # noqa: PLR2004 |
155 | | - json_response = json.loads(response["Payload"].read().decode("utf-8")) |
156 | | - return DurableExecutionInvocationOutput.from_dict(json_response) |
| 165 | + # Parameter validation |
| 166 | + if not function_name or not function_name.strip(): |
| 167 | + msg = "Function name is required" |
| 168 | + raise InvalidParameterValueException(msg) |
| 169 | + |
| 170 | + try: |
| 171 | + # Invoke AWS Lambda function using standard invoke method |
| 172 | + response = self.lambda_client.invoke( |
| 173 | + FunctionName=function_name, |
| 174 | + InvocationType="RequestResponse", # Synchronous invocation |
| 175 | + Payload=json.dumps(input.to_dict(), default=str), |
| 176 | + ) |
157 | 177 |
|
158 | | - msg: str = f"Lambda invocation failed with status code: {response['StatusCode']}, {response['Payload']=}" |
159 | | - raise DurableFunctionsTestError(msg) |
| 178 | + # Check HTTP status code |
| 179 | + status_code = response.get("StatusCode") |
| 180 | + if status_code not in (200, 202, 204): |
| 181 | + msg = f"Lambda invocation failed with status code: {status_code}" |
| 182 | + raise DurableFunctionsTestError(msg) |
| 183 | + |
| 184 | + # Check for function errors |
| 185 | + if "FunctionError" in response: |
| 186 | + error_payload = response["Payload"].read().decode("utf-8") |
| 187 | + msg = f"Lambda invocation failed with status {status_code}: {error_payload}" |
| 188 | + raise DurableFunctionsTestError(msg) |
| 189 | + |
| 190 | + # Parse response payload |
| 191 | + response_payload = response["Payload"].read().decode("utf-8") |
| 192 | + response_dict = json.loads(response_payload) |
| 193 | + |
| 194 | + # Convert to DurableExecutionInvocationOutput |
| 195 | + return DurableExecutionInvocationOutput.from_dict(response_dict) |
| 196 | + |
| 197 | + except self.lambda_client.exceptions.ResourceNotFoundException as e: |
| 198 | + msg = f"Function not found: {function_name}" |
| 199 | + raise ResourceNotFoundException(msg) from e |
| 200 | + except self.lambda_client.exceptions.InvalidParameterValueException as e: |
| 201 | + msg = f"Invalid parameter: {e}" |
| 202 | + raise InvalidParameterValueException(msg) from e |
| 203 | + except ( |
| 204 | + self.lambda_client.exceptions.TooManyRequestsException, |
| 205 | + self.lambda_client.exceptions.ServiceException, |
| 206 | + self.lambda_client.exceptions.ResourceConflictException, |
| 207 | + self.lambda_client.exceptions.InvalidRequestContentException, |
| 208 | + self.lambda_client.exceptions.RequestTooLargeException, |
| 209 | + self.lambda_client.exceptions.UnsupportedMediaTypeException, |
| 210 | + self.lambda_client.exceptions.InvalidRuntimeException, |
| 211 | + self.lambda_client.exceptions.InvalidZipFileException, |
| 212 | + self.lambda_client.exceptions.ResourceNotReadyException, |
| 213 | + self.lambda_client.exceptions.SnapStartTimeoutException, |
| 214 | + self.lambda_client.exceptions.SnapStartNotReadyException, |
| 215 | + self.lambda_client.exceptions.SnapStartException, |
| 216 | + self.lambda_client.exceptions.RecursiveInvocationException, |
| 217 | + ) as e: |
| 218 | + msg = f"Lambda invocation failed: {e}" |
| 219 | + raise DurableFunctionsTestError(msg) from e |
| 220 | + except ( |
| 221 | + self.lambda_client.exceptions.InvalidSecurityGroupIDException, |
| 222 | + self.lambda_client.exceptions.EC2ThrottledException, |
| 223 | + self.lambda_client.exceptions.EFSMountConnectivityException, |
| 224 | + self.lambda_client.exceptions.SubnetIPAddressLimitReachedException, |
| 225 | + self.lambda_client.exceptions.EC2UnexpectedException, |
| 226 | + self.lambda_client.exceptions.InvalidSubnetIDException, |
| 227 | + self.lambda_client.exceptions.EC2AccessDeniedException, |
| 228 | + self.lambda_client.exceptions.EFSIOException, |
| 229 | + self.lambda_client.exceptions.ENILimitReachedException, |
| 230 | + self.lambda_client.exceptions.EFSMountTimeoutException, |
| 231 | + self.lambda_client.exceptions.EFSMountFailureException, |
| 232 | + ) as e: |
| 233 | + msg = f"Lambda infrastructure error: {e}" |
| 234 | + raise DurableFunctionsTestError(msg) from e |
| 235 | + except ( |
| 236 | + self.lambda_client.exceptions.KMSAccessDeniedException, |
| 237 | + self.lambda_client.exceptions.KMSDisabledException, |
| 238 | + self.lambda_client.exceptions.KMSNotFoundException, |
| 239 | + self.lambda_client.exceptions.KMSInvalidStateException, |
| 240 | + ) as e: |
| 241 | + msg = f"Lambda KMS error: {e}" |
| 242 | + raise DurableFunctionsTestError(msg) from e |
| 243 | + except Exception as e: |
| 244 | + # Handle any remaining exceptions, including custom ones like DurableExecutionAlreadyStartedException |
| 245 | + if "DurableExecutionAlreadyStartedException" in str(type(e)): |
| 246 | + msg = f"Durable execution already started: {e}" |
| 247 | + raise DurableFunctionsTestError(msg) from e |
| 248 | + msg = f"Unexpected error during Lambda invocation: {e}" |
| 249 | + raise DurableFunctionsTestError(msg) from e |
0 commit comments