"""Lambda initiate-indexing function module.""" from content_utils.exceptions import IneligibleEventError from content_utils.logging.cdc_logging import ContentLambdaLoggerCDC from kafka_utils.consumer.message import debezium from kafka_utils.consumer.source.mapping import EventSourceMessage import sentry_sdk from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration from src import config from src.config import app_logger from src.constants import ADD_INDEX_OP from src.constants import STATUS_ERROR from src.constants import STATUS_OK from src.exceptions import ReviewQueueItemExplicitSkip from src.logic import event_handling from src.logic import feature from src.logic import sqs 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)] ) content_lambda_logger = ContentLambdaLoggerCDC(config.app_logger) SKIPPED_EXCEPTIONS = ( IneligibleEventError, ReviewQueueItemExplicitSkip ) def handler(event, context): """Lambda Entry point.""" add_inputs = [] other_indexing_inputs = [] status = STATUS_OK msk_messages = EventSourceMessage(event) for event_key, msk_message in msk_messages: content_lambda_logger.start(msk_message, event_key) try: result = process_event(msk_message) if result: if result.get('operation_type') == ADD_INDEX_OP: add_inputs.append(result) else: other_indexing_inputs.append(result) finally: content_lambda_logger.end() try: if feature.is_store_product_enabled(): # Publish add_to_index item operations to SQS status, add_inputs = start_store_product_flow(add_inputs) except Exception as e: status = STATUS_ERROR app_logger.error(f'{str(e)}') # Add any items that failed to publish to SQS back to other_indexing_inputs # so they can be processed via the Step Function as a fallback other_indexing_inputs.extend(add_inputs) # Send remaining items to Indexing Step Function if len(other_indexing_inputs) > 0: response = step_function.trigger_sfn({'data': {'indexing_inputs': other_indexing_inputs}}) execution_arn = response.get('executionArn') if response else None for item in other_indexing_inputs: app_logger.info( f'sfn execution: product_id={item.get("product_id")} ' f'review_queue_id={item.get("review_queue_id")} ' f'execution_arn={execution_arn}' ) return {'status': status} def start_store_product_flow(inputs): """Start store-product flow via publishing to SQS.""" failure_inputs = [] status = STATUS_OK for item in inputs: log_params = ( f'product_id={item.get("product_id")} ' f'review_queue_id={item.get("review_queue_id")} ' f'sqs={config.SQS_STORE_PRODUCT_QUEUE_NAME}' ) try: # 1) Send SQS message result = sqs.add_to_store_product_queue(item) message_id = result.get('MessageId') if result else None app_logger.info( f'published to sqs: {log_params} ' f'MessageId={message_id}' ) except Exception as e: # 2) Fallback: ensure the item is still processed by the Indexing Step Function failure_inputs.append(item) status = STATUS_ERROR app_logger.error(f'error: failed to publish to sqs {log_params} {str(e)}') return status, failure_inputs def process_event(msk_message): """Process MSK event.""" if not msk_message.value: content_lambda_logger.set_data(status='skip', result='no_message_body') return result = None try: if msk_message.topic != 'cdc.contentReview.reviewQueue': raise Exception(f'Topic {msk_message.topic} is not supported.') db_msg = debezium.DebeziumMessage( msk_message.value, msk_message.topic, allowed_event_ops=['c', 'u', 'd']) result = event_handling.parse_message_payload(db_msg) content_lambda_logger.set_data(status='success') except SKIPPED_EXCEPTIONS as e: content_lambda_logger.set_data(status='skip', result=str(e)) except Exception as e: content_lambda_logger.set_data(status=STATUS_ERROR, result=str(e)) raise e return result