"""Lambda module.""" import json from botocore.exceptions import WaiterError from content_utils.exceptions import IneligibleEventError from content_utils.exceptions import InvalidMessageException from content_utils.exceptions import NoProductDataException from content_utils.logging.logger import ContentLambdaLogger import sentry_sdk from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration from src import config from src.connectors.graphql import get_complete_product from src.constants import STATUS_ERROR from src.constants import STATUS_SKIP from src.constants import STATUS_SUCCESS from src.logic import feature_flag as ff from src.logic import s3 from src.logic import step_function if config.SENTRY_DSN: sentry_sdk.init( dsn=config.SENTRY_DSN, environment=config.ENVIRONMENT, integrations=[AwsLambdaIntegration(timeout_warning=True)] ) lambda_logger = ContentLambdaLogger(config.app_logger) def handler(event, context): """Lambda Entry point.""" batch_item_failures = [] lambda_logger.logger.debug(event) if not event.get('Records'): lambda_logger.logger.info('SQS has no records') for record in event.get('Records', []): try: lambda_logger.start() lambda_logger.set_data(event_key=f'sqs-{event.get("messageId")}') if not record.get('body'): raise InvalidMessageException('event missing "body"') msg_body = json.loads(record['body']) store_product_initiate_auto_approval(msg_body) lambda_logger.set_data(status=STATUS_SUCCESS) except ( InvalidMessageException, IneligibleEventError, NoProductDataException ) as e: lambda_logger.set_data(status=STATUS_SKIP, result=str(e)) except Exception as e: lambda_logger.set_data(status=STATUS_ERROR, result=str(e)) # Add failed message to batch failures for partial retry batch_item_failures.append({'itemIdentifier': record['messageId']}) finally: lambda_logger.end() # Return batch item failures for SQS partial batch failure handling return { 'batchItemFailures': batch_item_failures, } def store_product_initiate_auto_approval(msg_body): """Store product snapshot and initiate auto-approval sfn.""" product_id = msg_body.get('product_id', None) review_queue_id = msg_body.get('review_queue_id', None) operation_type = msg_body.get('operation_type', None) lambda_logger.set_data( queue_id=review_queue_id, product_id=product_id, operation_type=operation_type ) # Get complete product data hashed_data = json.dumps(msg_body) complete_product = get_complete_product(hashed_data) if not complete_product: raise NoProductDataException('Failed to query complete product') # Upload snapshot to S3 object_key = s3.get_object_key(product_id, review_queue_id) upload_status = s3.upload_snapshot(complete_product, object_key) try: s3.wait_until_exists(object_key) except WaiterError: raise Exception(f'Timed out waiting for S3 object to exist: {object_key}') snapshot_s3_url = s3.get_s3_url(config.AWS_BUCKET_NAME, object_key) lambda_logger.set_data( s3_upload_status=upload_status, snapshot_object_key=object_key, snapshot_bucket=config.AWS_BUCKET_NAME ) # Determine auto-approval eligibility based on feature flag use_auto_approval_decision = ff.is_eligible_for_auto_approval(complete_product) payload = { 'data': { 'product_id': msg_body.get('product_id'), 'review_queue_id': msg_body.get('review_queue_id'), 'use_auto_approval': use_auto_approval_decision, 'indexing_inputs': [msg_body], 'product_metadata_s3_url': snapshot_s3_url, 'is_integration_test': False } } # Start an auto-approval workflow execution execution_arn = step_function.invoke_auto_approval_sfn(payload) lambda_logger.set_data(execution_arn=execution_arn)