aws-lambda-powertools 3.30.0__tar.gz → 3.31.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/PKG-INFO +2 -2
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/params.py +45 -43
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/constants.py +3 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/version.py +1 -1
- aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/__init__.py +35 -0
- aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/base.py +248 -0
- aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/circuit_breaker.py +119 -0
- aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/config.py +128 -0
- aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/exceptions.py +77 -0
- aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/persistence/__init__.py +15 -0
- aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/persistence/base.py +291 -0
- aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/persistence/dynamodb.py +252 -0
- aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/persistence/record.py +63 -0
- aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/states.py +126 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/pyproject.toml +2 -2
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/setup.py +4 -2
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/LICENSE +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/README.md +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/THIRD-PARTY-LICENSES +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/api_gateway.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/appsync.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/bedrock_agent.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/bedrock_agent_function.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/content_types.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/depends.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/_registry.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/appsync_events.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/functions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/router.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/types.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/exception_handling.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/graphql_appsync/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/graphql_appsync/_registry.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/graphql_appsync/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/graphql_appsync/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/graphql_appsync/router.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/http_resolver.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/lambda_function_url.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/middlewares/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/middlewares/async_utils.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/middlewares/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/middlewares/openapi_validation.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/middlewares/schema_validation.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/compat.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/config.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/constants.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/dependant.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/encoders.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/merge.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/models.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/pydantic_loader.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/schema_generator.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/html.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/oauth2.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/swagger-ui-bundle.min.js +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/swagger-ui.min.css +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/types.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/request.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/router.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/types.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/util.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/vpc_lattice.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/exceptions/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/buffer/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/buffer/cache.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/buffer/config.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/buffer/functions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/buffer/handler.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/constants.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/correlation_paths.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/filters.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/formatter.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/formatters/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/formatters/datadog.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/lambda_context.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/logger.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/types.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/utils.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/functions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/metric.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/metrics.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/constants.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/metric_properties.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/types.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/cold_start.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/datadog/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/datadog/datadog.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/datadog/metrics.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/datadog/warnings.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/types.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/middleware_factory/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/middleware_factory/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/middleware_factory/factory.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/package_logger.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/py.typed +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/cache_dict.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/cookies.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/dynamodb_deserializer.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/functions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/headers_serializer.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/json_encoder.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/lazy_import.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/types.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/user_agent.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/tracing/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/tracing/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/tracing/extensions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/tracing/tracer.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/batch/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/batch/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/batch/decorators.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/batch/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/batch/sqs_fifo_partial_processor.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/batch/types.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/active_mq_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/alb_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/api_gateway_websocket_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/appsync/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/appsync/scalar_types_utils.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/appsync_authorizer_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/appsync_resolver_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/appsync_resolver_events_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/aws_config_rule_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/bedrock_agent_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/bedrock_agent_function_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/cloud_watch_alarm_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/cloud_watch_custom_widget_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/cloud_watch_logs_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/cloudformation_custom_resource_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/code_deploy_lifecycle_hook_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/code_pipeline_job_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/cognito_user_pool_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/common.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/connect_contact_flow_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/dynamo_db_stream_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/event_bridge_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/event_source.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/iot_registry_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/kafka_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/kinesis_firehose_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/kinesis_stream_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/lambda_function_url_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/rabbit_mq_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/s3_batch_operation_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/s3_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/s3_object_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/secrets_manager_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/ses_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/shared_functions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/sns_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/sqs_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/transfer_family_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/vpc_lattice.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/constants.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/provider/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/provider/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/provider/kms/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/provider/kms/aws_encryption_sdk.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/appconfig.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/comparators.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/constants.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/feature_flags.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/schema.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/types.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/config.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/hook.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/idempotency.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/persistence/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/persistence/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/persistence/cache.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/persistence/datarecord.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/persistence/redis.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/serialization/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/serialization/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/serialization/custom_dict.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/serialization/dataclass.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/serialization/functions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/serialization/no_op.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/serialization/pydantic.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/jmespath_utils/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/jmespath_utils/envelopes.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/consumer_records.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/deserializer/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/deserializer/avro.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/deserializer/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/deserializer/default.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/deserializer/deserializer.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/deserializer/json.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/deserializer/protobuf.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/kafka_consumer.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/schema_config.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/serialization/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/serialization/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/serialization/custom_dict.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/serialization/dataclass.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/serialization/pydantic.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/serialization/serialization.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/serialization/types.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/metadata/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/metadata/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/metadata/lambda_metadata.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/appconfig.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/constants.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/dynamodb.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/secrets.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/ssm.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/types.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/apigw.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/apigw_websocket.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/apigwv2.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/bedrock_agent.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/cloudwatch.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/dynamodb.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/event_bridge.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/kafka.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/kinesis.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/kinesis_firehose.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/lambda_function_url.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/sns.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/sqs.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/vpc_lattice.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/vpc_latticev2.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/functions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/alb.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/apigw.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/apigw_websocket.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/apigwv2.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/appsync.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/appsync_events.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/bedrock_agent.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/cloudformation_custom_resource.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/cloudwatch.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/cognito.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/dynamodb.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/event_bridge.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/iot_registry_events.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/kafka.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/kinesis.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/kinesis_firehose.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/kinesis_firehose_sqs.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/lambda_function_url.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/s3.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/s3_batch_operation.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/s3_event_notification.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/s3_object_event.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/ses.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/sns.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/sqs.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/transfer_family.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/vpc_lattice.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/vpc_latticev2.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/parser.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/types.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/serialization.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/_s3_seekable_io.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/compat.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/constants.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/s3_object.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/transformations/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/transformations/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/transformations/csv.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/transformations/gzip.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/transformations/zip.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/types.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/typing/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/typing/lambda_client_context.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/typing/lambda_client_context_mobile_client.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/typing/lambda_cognito_identity.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/typing/lambda_context.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/validation/__init__.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/validation/base.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/validation/envelopes.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/validation/exceptions.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/validation/validator.py +0 -0
- {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/warnings/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: aws_lambda_powertools
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.31.0
|
|
4
4
|
Summary: Powertools for AWS Lambda (Python) is a developer toolkit to implement Serverless best practices and increase developer velocity.
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: aws_lambda_powertools,aws,tracing,logging,lambda,powertools,feature_flags,idempotency,middleware
|
|
@@ -39,7 +39,7 @@ Requires-Dist: jsonpath-ng (>=1.6.0,<2.0.0) ; extra == "all" or extra == "datama
|
|
|
39
39
|
Requires-Dist: protobuf (>=6.30.2,<8.0.0) ; extra == "kafka-consumer-protobuf"
|
|
40
40
|
Requires-Dist: pydantic (>=2.4.0,<3.0.0) ; extra == "parser" or extra == "all"
|
|
41
41
|
Requires-Dist: pydantic-settings (>=2.6.1,<3.0.0) ; extra == "all"
|
|
42
|
-
Requires-Dist: redis (>=4.4,<
|
|
42
|
+
Requires-Dist: redis (>=4.4,<9.0) ; extra == "redis"
|
|
43
43
|
Requires-Dist: typing-extensions (>=4.11.0,<5.0.0)
|
|
44
44
|
Requires-Dist: valkey-glide (>=1.3.5,<3.0) ; extra == "valkey"
|
|
45
45
|
Project-URL: Documentation, https://docs.powertools.aws.dev/lambda/python/
|
|
@@ -953,54 +953,52 @@ def get_field_info_response_type(annotation, value) -> tuple[FieldInfo | None, A
|
|
|
953
953
|
return get_field_info_and_type_annotation(inner_type, value, False, True)
|
|
954
954
|
|
|
955
955
|
|
|
956
|
-
def
|
|
957
|
-
"""Check if a FieldInfo has a discriminator."""
|
|
958
|
-
return hasattr(field_info, "discriminator") and field_info.discriminator is not None
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
def _handle_discriminator_with_param(
|
|
956
|
+
def _split_location_marker_and_field(
|
|
962
957
|
annotations: list[FieldInfo],
|
|
963
|
-
|
|
964
|
-
) -> tuple[FieldInfo | None, Any, bool]:
|
|
958
|
+
) -> tuple[FieldInfo, FieldInfo]:
|
|
965
959
|
"""
|
|
966
|
-
|
|
960
|
+
Split a pair of FieldInfo into the Powertools location marker and the plain Pydantic Field.
|
|
961
|
+
|
|
962
|
+
A parameter like ``Annotated[str, Field(gt=0), Query()]`` flattens to two FieldInfo: the
|
|
963
|
+
location marker (``Path``/``Query``/``Header``/``Body``, a ``Param`` or ``Body`` subclass) and
|
|
964
|
+
a plain Pydantic ``Field`` carrying constraints. We keep them apart so the location marker
|
|
965
|
+
drives where the value comes from, while the ``Field``'s constraints/metadata still apply.
|
|
967
966
|
|
|
968
967
|
Returns:
|
|
969
|
-
tuple of (
|
|
968
|
+
tuple of (location_marker, plain_field)
|
|
970
969
|
"""
|
|
971
|
-
|
|
972
|
-
|
|
970
|
+
location_marker: FieldInfo | None = None
|
|
971
|
+
plain_field: FieldInfo | None = None
|
|
973
972
|
|
|
974
973
|
for ann in annotations:
|
|
975
|
-
if isinstance(ann, Body):
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
974
|
+
if isinstance(ann, (Param, Body)):
|
|
975
|
+
location_marker = ann
|
|
976
|
+
else:
|
|
977
|
+
plain_field = ann
|
|
979
978
|
|
|
980
|
-
if
|
|
981
|
-
|
|
982
|
-
return body_obj, annotation, True
|
|
979
|
+
if location_marker is None or plain_field is None:
|
|
980
|
+
raise AssertionError("Only one FieldInfo can be used per parameter")
|
|
983
981
|
|
|
984
|
-
|
|
982
|
+
return location_marker, plain_field
|
|
985
983
|
|
|
986
984
|
|
|
987
985
|
def _create_field_info(
|
|
988
986
|
powertools_annotation: FieldInfo,
|
|
989
987
|
type_annotation: Any,
|
|
990
|
-
|
|
988
|
+
preserve_full_annotation: bool,
|
|
991
989
|
) -> FieldInfo:
|
|
992
990
|
"""Create or copy FieldInfo based on the annotation type."""
|
|
993
|
-
field_info
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
991
|
+
# Copy field_info because we mutate field_info.default later.
|
|
992
|
+
field_info = copy_field_info(
|
|
993
|
+
field_info=powertools_annotation,
|
|
994
|
+
annotation=type_annotation,
|
|
995
|
+
)
|
|
996
|
+
if preserve_full_annotation:
|
|
997
|
+
# The location marker is paired with a plain Field (constraints or discriminator).
|
|
998
|
+
# copy_field_info strips the Pydantic Field out of the metadata, so re-attach the full
|
|
999
|
+
# Annotated type here, that's what makes the Field's metadata flow into the TypeAdapter
|
|
1000
|
+
# that ModelField builds for validation.
|
|
997
1001
|
field_info.annotation = type_annotation
|
|
998
|
-
else:
|
|
999
|
-
# Copy field_info because we mutate field_info.default later
|
|
1000
|
-
field_info = copy_field_info(
|
|
1001
|
-
field_info=powertools_annotation,
|
|
1002
|
-
annotation=type_annotation,
|
|
1003
|
-
)
|
|
1004
1002
|
return field_info
|
|
1005
1003
|
|
|
1006
1004
|
|
|
@@ -1043,13 +1041,16 @@ def get_field_info_annotated_type(annotation, value, is_path_param: bool) -> tup
|
|
|
1043
1041
|
|
|
1044
1042
|
# Determine which annotation to use
|
|
1045
1043
|
powertools_annotation: FieldInfo | None = None
|
|
1046
|
-
|
|
1044
|
+
# When a plain Pydantic Field is paired with a location marker (e.g. Field(gt=0) + Query),
|
|
1045
|
+
# we keep the full Annotated type as the annotation so the Field's metadata still validates.
|
|
1046
|
+
preserve_full_annotation = False
|
|
1047
1047
|
|
|
1048
1048
|
if len(powertools_annotations) == 2:
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
)
|
|
1049
|
+
# A location marker (Path/Query/Header/Body) plus a plain Pydantic Field carrying
|
|
1050
|
+
# constraints, a discriminator, or any other Field setting. The marker says where the
|
|
1051
|
+
# value comes from; the Field says how to validate it.
|
|
1052
|
+
powertools_annotation, _ = _split_location_marker_and_field(powertools_annotations)
|
|
1053
|
+
preserve_full_annotation = True
|
|
1053
1054
|
elif len(powertools_annotations) > 1:
|
|
1054
1055
|
raise AssertionError("Only one FieldInfo can be used per parameter")
|
|
1055
1056
|
else:
|
|
@@ -1057,18 +1058,19 @@ def get_field_info_annotated_type(annotation, value, is_path_param: bool) -> tup
|
|
|
1057
1058
|
|
|
1058
1059
|
# Reconstruct type_annotation with non-FieldInfo metadata if present
|
|
1059
1060
|
# This ensures constraints like Interval are preserved
|
|
1060
|
-
if other_metadata and not
|
|
1061
|
+
if other_metadata and not preserve_full_annotation:
|
|
1061
1062
|
type_annotation = Annotated[(type_annotation, *other_metadata)]
|
|
1062
1063
|
|
|
1063
1064
|
# Process the annotation if it exists
|
|
1064
1065
|
field_info: FieldInfo | None = None
|
|
1065
|
-
if isinstance(powertools_annotation, FieldInfo):
|
|
1066
|
-
|
|
1066
|
+
if isinstance(powertools_annotation, FieldInfo):
|
|
1067
|
+
# When pairing a location marker with a plain Field, hand the full Annotated[...] to the
|
|
1068
|
+
# field so the Field's constraints/discriminator flow into the validating TypeAdapter.
|
|
1069
|
+
field_annotation = annotation if preserve_full_annotation else type_annotation
|
|
1070
|
+
field_info = _create_field_info(powertools_annotation, field_annotation, preserve_full_annotation)
|
|
1067
1071
|
_set_field_default(field_info, value, is_path_param)
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
if _has_discriminator(powertools_annotation): # pragma: no cover
|
|
1071
|
-
type_annotation = annotation # pragma: no cover
|
|
1072
|
+
if preserve_full_annotation:
|
|
1073
|
+
type_annotation = annotation
|
|
1072
1074
|
|
|
1073
1075
|
return field_info, type_annotation
|
|
1074
1076
|
|
aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/__init__.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Circuit Breaker utility for protecting unhealthy downstream dependencies.
|
|
3
|
+
|
|
4
|
+
!!! warning "Alpha / experimental"
|
|
5
|
+
This utility is published under the `_alpha` namespace while we collect
|
|
6
|
+
feedback. The public API may change in a backwards-incompatible way before it
|
|
7
|
+
is promoted to GA. Pin your version and follow the tracking discussion before
|
|
8
|
+
relying on it in production.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from aws_lambda_powertools.utilities.circuit_breaker_alpha.circuit_breaker import circuit_breaker
|
|
12
|
+
from aws_lambda_powertools.utilities.circuit_breaker_alpha.config import CircuitBreakerConfig
|
|
13
|
+
from aws_lambda_powertools.utilities.circuit_breaker_alpha.exceptions import (
|
|
14
|
+
CircuitBreakerConfigError,
|
|
15
|
+
CircuitBreakerError,
|
|
16
|
+
CircuitBreakerOpenError,
|
|
17
|
+
CircuitBreakerPersistenceError,
|
|
18
|
+
)
|
|
19
|
+
from aws_lambda_powertools.utilities.circuit_breaker_alpha.states import (
|
|
20
|
+
CircuitInfo,
|
|
21
|
+
CircuitState,
|
|
22
|
+
CircuitTransition,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
__all__ = (
|
|
26
|
+
"circuit_breaker",
|
|
27
|
+
"CircuitBreakerConfig",
|
|
28
|
+
"CircuitInfo",
|
|
29
|
+
"CircuitState",
|
|
30
|
+
"CircuitTransition",
|
|
31
|
+
"CircuitBreakerError",
|
|
32
|
+
"CircuitBreakerOpenError",
|
|
33
|
+
"CircuitBreakerConfigError",
|
|
34
|
+
"CircuitBreakerPersistenceError",
|
|
35
|
+
)
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Orchestrator for the Circuit Breaker utility.
|
|
3
|
+
|
|
4
|
+
:class:`CircuitBreakerHandler` owns the state machine and the per-environment failure
|
|
5
|
+
counter; the persistence layer owns the shared truth. This split keeps the healthy
|
|
6
|
+
path write-free: failures are counted locally and only persisted on a state transition.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import datetime
|
|
12
|
+
import logging
|
|
13
|
+
import uuid
|
|
14
|
+
from typing import TYPE_CHECKING, Any
|
|
15
|
+
|
|
16
|
+
from aws_lambda_powertools.utilities.circuit_breaker_alpha.exceptions import CircuitBreakerOpenError
|
|
17
|
+
from aws_lambda_powertools.utilities.circuit_breaker_alpha.states import CircuitState, CircuitTransition
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from collections.abc import Callable
|
|
21
|
+
|
|
22
|
+
from aws_lambda_powertools.utilities.circuit_breaker_alpha.config import CircuitBreakerConfig
|
|
23
|
+
from aws_lambda_powertools.utilities.circuit_breaker_alpha.persistence.base import (
|
|
24
|
+
CircuitBreakerPersistenceLayer,
|
|
25
|
+
)
|
|
26
|
+
from aws_lambda_powertools.utilities.circuit_breaker_alpha.states import CircuitInfo
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
# Per-environment, per-circuit consecutive counters. Module-level so they survive across
|
|
31
|
+
# invocations within the same execution environment, the same way idempotency caches do.
|
|
32
|
+
_LOCAL_FAILURES: dict[str, int] = {}
|
|
33
|
+
_LOCAL_SUCCESSES: dict[str, int] = {}
|
|
34
|
+
|
|
35
|
+
# Tracks the last state this environment observed from the store, per circuit. Used to
|
|
36
|
+
# detect transitions back to CLOSED that happened externally (another env tripped and
|
|
37
|
+
# recovered), so stale local failure streaks can be invalidated.
|
|
38
|
+
_LAST_OBSERVED_STATE: dict[str, CircuitState] = {}
|
|
39
|
+
|
|
40
|
+
# Stable per-environment identifier used to claim the half-open probe lock.
|
|
41
|
+
_ENVIRONMENT_ID = uuid.uuid4().hex
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class CircuitBreakerHandler:
|
|
45
|
+
"""
|
|
46
|
+
Drive a single protected call through the circuit breaker state machine.
|
|
47
|
+
|
|
48
|
+
A new handler is created per invocation by the decorator. It reads the shared state,
|
|
49
|
+
routes the call (run, short-circuit, or probe), and records the outcome.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
function : Callable
|
|
54
|
+
The protected function.
|
|
55
|
+
name : str
|
|
56
|
+
Circuit name.
|
|
57
|
+
config : CircuitBreakerConfig
|
|
58
|
+
Circuit configuration.
|
|
59
|
+
persistence_store : CircuitBreakerPersistenceLayer
|
|
60
|
+
Shared state store.
|
|
61
|
+
on_circuit_open : Callable | None
|
|
62
|
+
Callback invoked with the protected call's own ``*args``/``**kwargs`` plus a
|
|
63
|
+
trailing ``circuit`` keyword argument when the circuit is open. If ``None``, an
|
|
64
|
+
open circuit raises :class:`CircuitBreakerOpenError`.
|
|
65
|
+
function_args : tuple
|
|
66
|
+
Positional arguments the protected function was called with.
|
|
67
|
+
function_kwargs : dict
|
|
68
|
+
Keyword arguments the protected function was called with.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
def __init__(
|
|
72
|
+
self,
|
|
73
|
+
function: Callable,
|
|
74
|
+
name: str,
|
|
75
|
+
config: CircuitBreakerConfig,
|
|
76
|
+
persistence_store: CircuitBreakerPersistenceLayer,
|
|
77
|
+
on_circuit_open: Callable | None = None,
|
|
78
|
+
on_transition: Callable | None = None,
|
|
79
|
+
function_args: tuple | None = None,
|
|
80
|
+
function_kwargs: dict | None = None,
|
|
81
|
+
):
|
|
82
|
+
self.function = function
|
|
83
|
+
self.name = name
|
|
84
|
+
self.config = config
|
|
85
|
+
self.on_circuit_open = on_circuit_open
|
|
86
|
+
self.on_transition = on_transition
|
|
87
|
+
self.fn_args = function_args or ()
|
|
88
|
+
self.fn_kwargs = function_kwargs or {}
|
|
89
|
+
|
|
90
|
+
persistence_store.configure(config=config, circuit_name=name)
|
|
91
|
+
self.persistence_store = persistence_store
|
|
92
|
+
|
|
93
|
+
def handle(self) -> Any:
|
|
94
|
+
"""
|
|
95
|
+
Evaluate the circuit and route the call.
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
Any
|
|
100
|
+
The protected function's result when the call runs, or the
|
|
101
|
+
``on_circuit_open`` callback's return value when the circuit is open.
|
|
102
|
+
|
|
103
|
+
Raises
|
|
104
|
+
------
|
|
105
|
+
CircuitBreakerOpenError
|
|
106
|
+
If the circuit is open and no callback is registered.
|
|
107
|
+
"""
|
|
108
|
+
record = self.persistence_store.get_state(self.name)
|
|
109
|
+
|
|
110
|
+
if record.state == CircuitState.CLOSED:
|
|
111
|
+
# If we previously observed a non-CLOSED state and the circuit is now back to
|
|
112
|
+
# CLOSED, another environment completed the recovery cycle. Reset local counters
|
|
113
|
+
# so a stale partial failure streak doesn't immediately re-trip the circuit.
|
|
114
|
+
prev = _LAST_OBSERVED_STATE.get(self.name)
|
|
115
|
+
if prev is not None and prev != CircuitState.CLOSED:
|
|
116
|
+
_LOCAL_FAILURES[self.name] = 0
|
|
117
|
+
_LAST_OBSERVED_STATE[self.name] = CircuitState.CLOSED
|
|
118
|
+
return self._call_closed()
|
|
119
|
+
|
|
120
|
+
if record.state == CircuitState.OPEN:
|
|
121
|
+
_LAST_OBSERVED_STATE[self.name] = CircuitState.OPEN
|
|
122
|
+
# ``opened_at`` may legitimately be 0 (epoch); treat only None as missing.
|
|
123
|
+
opened_at = record.opened_at if record.opened_at is not None else self._now()
|
|
124
|
+
if self._now() >= opened_at + self.config.recovery_timeout:
|
|
125
|
+
# Recovery window elapsed: try to become the single prober.
|
|
126
|
+
if self.persistence_store.try_acquire_half_open(self.name, _ENVIRONMENT_ID, opened_at):
|
|
127
|
+
self._notify(CircuitState.OPEN, CircuitState.HALF_OPEN, opened_at=opened_at)
|
|
128
|
+
return self._call_probe()
|
|
129
|
+
return self._open_response(record.to_circuit_info())
|
|
130
|
+
|
|
131
|
+
# HALF_OPEN: only the environment that owns the probe lock runs.
|
|
132
|
+
_LAST_OBSERVED_STATE[self.name] = CircuitState.HALF_OPEN
|
|
133
|
+
if record.half_open_owner == _ENVIRONMENT_ID:
|
|
134
|
+
return self._call_probe()
|
|
135
|
+
|
|
136
|
+
# If the probe lease has expired (owner recycled mid-probe), take over.
|
|
137
|
+
if record.probe_lease_expiry is not None and self._now() >= record.probe_lease_expiry:
|
|
138
|
+
logger.debug("Circuit '%s' probe lease expired; attempting takeover.", self.name)
|
|
139
|
+
if self.persistence_store.try_acquire_half_open(self.name, _ENVIRONMENT_ID, record.opened_at or 0):
|
|
140
|
+
return self._call_probe()
|
|
141
|
+
|
|
142
|
+
return self._open_response(record.to_circuit_info())
|
|
143
|
+
|
|
144
|
+
def _call_closed(self) -> Any:
|
|
145
|
+
"""Run the protected call while the circuit is closed, tracking failures."""
|
|
146
|
+
try:
|
|
147
|
+
result = self.function(*self.fn_args, **self.fn_kwargs)
|
|
148
|
+
except Exception as exc:
|
|
149
|
+
if not self.config.counts_as_failure(exc):
|
|
150
|
+
raise
|
|
151
|
+
failures = _LOCAL_FAILURES.get(self.name, 0) + 1
|
|
152
|
+
_LOCAL_FAILURES[self.name] = failures
|
|
153
|
+
if failures >= self.config.failure_threshold:
|
|
154
|
+
logger.debug("Circuit '%s' tripping CLOSED to OPEN after %d failures.", self.name, failures)
|
|
155
|
+
opened_at = self._now()
|
|
156
|
+
self._safe_persist(
|
|
157
|
+
self.persistence_store.save_open,
|
|
158
|
+
self.name,
|
|
159
|
+
failure_count=failures,
|
|
160
|
+
opened_at=opened_at,
|
|
161
|
+
)
|
|
162
|
+
_LOCAL_FAILURES[self.name] = 0
|
|
163
|
+
self._notify(CircuitState.CLOSED, CircuitState.OPEN, opened_at=opened_at)
|
|
164
|
+
raise
|
|
165
|
+
else:
|
|
166
|
+
_LOCAL_FAILURES[self.name] = 0
|
|
167
|
+
return result
|
|
168
|
+
|
|
169
|
+
def _call_probe(self) -> Any:
|
|
170
|
+
"""Run a probe during half-open, closing or reopening based on the outcome."""
|
|
171
|
+
try:
|
|
172
|
+
result = self.function(*self.fn_args, **self.fn_kwargs)
|
|
173
|
+
except Exception as exc:
|
|
174
|
+
if not self.config.counts_as_failure(exc):
|
|
175
|
+
raise
|
|
176
|
+
logger.debug("Circuit '%s' probe failed; reopening.", self.name)
|
|
177
|
+
opened_at = self._now()
|
|
178
|
+
self._safe_persist(self.persistence_store.save_reopen, self.name, opened_at=opened_at)
|
|
179
|
+
_LOCAL_SUCCESSES[self.name] = 0
|
|
180
|
+
self._notify(CircuitState.HALF_OPEN, CircuitState.OPEN, opened_at=opened_at)
|
|
181
|
+
raise
|
|
182
|
+
else:
|
|
183
|
+
successes = _LOCAL_SUCCESSES.get(self.name, 0) + 1
|
|
184
|
+
_LOCAL_SUCCESSES[self.name] = successes
|
|
185
|
+
if successes >= self.config.success_threshold:
|
|
186
|
+
logger.debug("Circuit '%s' closing after %d probe successes.", self.name, successes)
|
|
187
|
+
self._safe_persist(self.persistence_store.save_closed, self.name)
|
|
188
|
+
_LOCAL_SUCCESSES[self.name] = 0
|
|
189
|
+
_LOCAL_FAILURES[self.name] = 0
|
|
190
|
+
self._notify(CircuitState.HALF_OPEN, CircuitState.CLOSED)
|
|
191
|
+
return result
|
|
192
|
+
|
|
193
|
+
def _safe_persist(self, fn: Callable, *args: Any, **kwargs: Any) -> None:
|
|
194
|
+
"""
|
|
195
|
+
Call a persistence write, swallowing and logging failures.
|
|
196
|
+
|
|
197
|
+
State-transition writes must never mask the downstream's real result or replace
|
|
198
|
+
the downstream's real exception. This mirrors the fail-open read policy in the
|
|
199
|
+
persistence layer.
|
|
200
|
+
"""
|
|
201
|
+
try:
|
|
202
|
+
fn(*args, **kwargs)
|
|
203
|
+
except Exception:
|
|
204
|
+
logger.warning(
|
|
205
|
+
"Circuit '%s': persistence write (%s) failed; the transition may be delayed but the "
|
|
206
|
+
"downstream result is preserved.",
|
|
207
|
+
self.name,
|
|
208
|
+
getattr(fn, "__name__", repr(fn)),
|
|
209
|
+
exc_info=True,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
def _open_response(self, circuit: CircuitInfo) -> Any:
|
|
213
|
+
"""Produce the response for an open circuit: callback result or raise."""
|
|
214
|
+
if self.on_circuit_open is not None:
|
|
215
|
+
# Forward the protected call's arguments unchanged: positional stay positional,
|
|
216
|
+
# keyword stay keyword. The circuit snapshot is passed as a keyword argument so
|
|
217
|
+
# it never collides with positionalized kwargs nor depends on dict ordering.
|
|
218
|
+
return self.on_circuit_open(*self.fn_args, **self.fn_kwargs, circuit=circuit)
|
|
219
|
+
raise CircuitBreakerOpenError(
|
|
220
|
+
f"Circuit '{self.name}' is open.",
|
|
221
|
+
circuit=circuit,
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
def _notify(self, from_state: CircuitState, to_state: CircuitState, opened_at: int | None = None) -> None:
|
|
225
|
+
"""
|
|
226
|
+
Fire the ``on_transition`` hook for a state change.
|
|
227
|
+
|
|
228
|
+
Called only on real transitions, never on the hot path. Any exception the hook
|
|
229
|
+
raises is swallowed and logged: observability must never break the protected call.
|
|
230
|
+
"""
|
|
231
|
+
if self.on_transition is None:
|
|
232
|
+
return
|
|
233
|
+
try:
|
|
234
|
+
self.on_transition(
|
|
235
|
+
CircuitTransition(
|
|
236
|
+
circuit_name=self.name,
|
|
237
|
+
from_state=from_state,
|
|
238
|
+
to_state=to_state,
|
|
239
|
+
opened_at=opened_at,
|
|
240
|
+
),
|
|
241
|
+
)
|
|
242
|
+
except Exception:
|
|
243
|
+
logger.warning("on_transition hook for circuit '%s' raised; ignoring.", self.name, exc_info=True)
|
|
244
|
+
|
|
245
|
+
@staticmethod
|
|
246
|
+
def _now() -> int:
|
|
247
|
+
"""Current unix timestamp in seconds."""
|
|
248
|
+
return int(datetime.datetime.now().timestamp())
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Primary interface for the Circuit Breaker utility.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import functools
|
|
8
|
+
import logging
|
|
9
|
+
import os
|
|
10
|
+
import warnings
|
|
11
|
+
from typing import TYPE_CHECKING, Any
|
|
12
|
+
|
|
13
|
+
from aws_lambda_powertools.shared import constants
|
|
14
|
+
from aws_lambda_powertools.shared.functions import strtobool
|
|
15
|
+
from aws_lambda_powertools.utilities.circuit_breaker_alpha.base import CircuitBreakerHandler
|
|
16
|
+
from aws_lambda_powertools.utilities.circuit_breaker_alpha.config import CircuitBreakerConfig
|
|
17
|
+
from aws_lambda_powertools.warnings import PowertoolsUserWarning
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from collections.abc import Callable
|
|
21
|
+
|
|
22
|
+
from aws_lambda_powertools.utilities.circuit_breaker_alpha.persistence.base import (
|
|
23
|
+
CircuitBreakerPersistenceLayer,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def circuit_breaker(
|
|
30
|
+
name: str,
|
|
31
|
+
persistence_store: CircuitBreakerPersistenceLayer,
|
|
32
|
+
on_circuit_open: Callable | None = None,
|
|
33
|
+
on_transition: Callable | None = None,
|
|
34
|
+
config: CircuitBreakerConfig | None = None,
|
|
35
|
+
) -> Callable:
|
|
36
|
+
"""
|
|
37
|
+
Protect a function that calls an unhealthy-prone downstream with a circuit breaker.
|
|
38
|
+
|
|
39
|
+
Wrap the function that makes the downstream call, not the whole Lambda handler, so a
|
|
40
|
+
tripped circuit reflects one dependency rather than unrelated handler logic.
|
|
41
|
+
|
|
42
|
+
When the circuit is open the protected function is not called. Instead, if an
|
|
43
|
+
``on_circuit_open`` callback is registered it runs and its return value becomes the
|
|
44
|
+
call's result; otherwise :class:`CircuitBreakerOpenError` is raised.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
name : str
|
|
49
|
+
Unique circuit name. Each name is an independent circuit; a function calling
|
|
50
|
+
several backends should use one circuit per backend.
|
|
51
|
+
persistence_store : CircuitBreakerPersistenceLayer
|
|
52
|
+
Shared state store (for example ``CircuitBreakerDynamoDBPersistence``).
|
|
53
|
+
on_circuit_open : Callable | None
|
|
54
|
+
Called when the circuit is open, with the protected function's own arguments
|
|
55
|
+
(positional stay positional, keyword stay keyword) plus a trailing ``circuit``
|
|
56
|
+
keyword argument carrying a ``CircuitInfo``. Its return value becomes the call's
|
|
57
|
+
result. If ``None``, an open circuit raises ``CircuitBreakerOpenError``.
|
|
58
|
+
on_transition : Callable | None
|
|
59
|
+
Called with a single ``CircuitTransition`` argument whenever the circuit changes
|
|
60
|
+
state (open, probe, close, reopen). Fires only on transitions, never on the
|
|
61
|
+
per-invocation hot path, so it is a safe place to emit a CloudWatch metric. Any
|
|
62
|
+
exception it raises is swallowed and logged so observability never breaks the
|
|
63
|
+
protected call.
|
|
64
|
+
config : CircuitBreakerConfig | None
|
|
65
|
+
Tunables. Defaults to ``CircuitBreakerConfig()`` when omitted.
|
|
66
|
+
|
|
67
|
+
Returns
|
|
68
|
+
-------
|
|
69
|
+
Callable
|
|
70
|
+
The decorated function.
|
|
71
|
+
|
|
72
|
+
Example
|
|
73
|
+
-------
|
|
74
|
+
**Protect a payment backend, buffering rejected requests**
|
|
75
|
+
|
|
76
|
+
from aws_lambda_powertools.utilities.circuit_breaker_alpha import circuit_breaker, CircuitInfo
|
|
77
|
+
from aws_lambda_powertools.utilities.circuit_breaker_alpha.persistence import (
|
|
78
|
+
CircuitBreakerDynamoDBPersistence,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
persistence = CircuitBreakerDynamoDBPersistence(table_name="CircuitBreakerState")
|
|
82
|
+
|
|
83
|
+
def buffer(order: dict, circuit: CircuitInfo):
|
|
84
|
+
sqs.send_message(QueueUrl=url, MessageBody=json.dumps(order))
|
|
85
|
+
|
|
86
|
+
@circuit_breaker(name="payment-backend", persistence_store=persistence, on_circuit_open=buffer)
|
|
87
|
+
def charge(order: dict) -> dict:
|
|
88
|
+
return payment_api.charge(order)
|
|
89
|
+
"""
|
|
90
|
+
config = config or CircuitBreakerConfig()
|
|
91
|
+
|
|
92
|
+
def decorator(function: Callable) -> Callable:
|
|
93
|
+
@functools.wraps(function)
|
|
94
|
+
def wrapper(*args, **kwargs) -> Any:
|
|
95
|
+
# Skip the circuit entirely when disabled (development only).
|
|
96
|
+
if strtobool(os.getenv(constants.CIRCUIT_BREAKER_DISABLED_ENV, "false")):
|
|
97
|
+
warnings.warn(
|
|
98
|
+
message="Disabling the circuit breaker is intended for development environments only "
|
|
99
|
+
"and should not be used in production.",
|
|
100
|
+
category=PowertoolsUserWarning,
|
|
101
|
+
stacklevel=2,
|
|
102
|
+
)
|
|
103
|
+
return function(*args, **kwargs)
|
|
104
|
+
|
|
105
|
+
handler = CircuitBreakerHandler(
|
|
106
|
+
function=function,
|
|
107
|
+
name=name,
|
|
108
|
+
config=config,
|
|
109
|
+
persistence_store=persistence_store,
|
|
110
|
+
on_circuit_open=on_circuit_open,
|
|
111
|
+
on_transition=on_transition,
|
|
112
|
+
function_args=args,
|
|
113
|
+
function_kwargs=kwargs,
|
|
114
|
+
)
|
|
115
|
+
return handler.handle()
|
|
116
|
+
|
|
117
|
+
return wrapper
|
|
118
|
+
|
|
119
|
+
return decorator
|