"""Lambda submit_product function module.""" from typing import Any from common.connectors import graphql from common.schemas.ingestion import Event, ProductInfo from lambdacommon.common_config import logger import config from src.constants import MISSING_ARTWORK, MISSING_AUDIO, RetrySubmitException def handler(event_data: dict[str, Any], context: Any) -> dict[str, Any]: """ Lambda entry point. Args: event_data: Lambda event payload (should look like event.shadow.json) context: Lambda context. """ event = Event(**event_data) correlation_id = event.correlation_id execution_arn = event.execution_arn assert execution_arn event.product_info = handle( event.product_info, event.bulk_session_ingestion_id, execution_arn, correlation_id, ) return event.model_dump() def handle( product_info: ProductInfo, ingestion_id: str, execution_arn: str, correlation_id: str, ) -> ProductInfo: product = product_info.product tracks = product_info.tracks or [] if not product.product_id or not product.upc or not product.vendor_id: logger.info("Missing required data for execution.") return product_info graphql.init_graphql_client( environment=config.ENVIRONMENT, service_name=config.M2M_APPLICATION_NAME, graphql_service_name=config.GRAPHQL_SERVICE_NAME, identity_id=config.IDENTITY_ID, profile_id=config.PROFILE_ID, profile_type=config.PROFILE_TYPE, headers={ "Correlation-Id": correlation_id, "Orchard-Roles": config.ROLE, }, ) # Since the submit step is optional, if it fails we don't want to fail the ingest # We raise an exception to try again but after X attempts the exception is ignored # The only failure case is when it fails to set the submit status of the product submitted = False error_message = "" try: if not product.artwork or any(not track.asset for track in tracks): logger.info("Skip validate/submit logic. Missing assets") return product_info validation_errors = graphql.validate_product(product.product_id) logger.info(f"Validated {product.product_id} - {validation_errors}") if check_missing_assets(validation_errors): logger.info("Skip validate/submit logic. Missing assets") return product_info # Check if the product is already submitted which can happen if this is a retry gql_product = graphql.get_product_by_upc(product.upc) submitted = bool( gql_product and gql_product.release_status == "transfer_to_content" ) if not validation_errors and not submitted: result = graphql.submit_product( product.product_id, product.vendor_id, product.subaccount_id ) logger.info(f"Submit product {product.product_id} result: {result}") submitted = True except Exception as e: error_message = str(e) logger.error(f"Failed to submit the product: {error_message}") logger.info(f"Update product {product.product_id} submitted={submitted}") graphql.upsert_bulk_session_ingestion_product( bulk_session_ingestion_id=ingestion_id, execution_arn=execution_arn, product_code=product.release_reference, submit_status="success" if submitted else "failure", ) # Do this after updating the submit status so that if the retry limit is reached # and this exception is ignored the product submit status was set to "failure" if error_message: raise RetrySubmitException(error_message) return product_info def check_missing_assets(validation_errors: dict[str, Any] | None) -> bool: if not validation_errors: return False missing_assets = False for product_error in validation_errors["validation"]["errors"] or []: if product_error.get("reason") == MISSING_ARTWORK: missing_assets = True for track in validation_errors["tracks"] or []: for track_error in track["validation"]["errors"] or []: if track_error.get("reason") == MISSING_AUDIO: missing_assets = True return missing_assets