88
99import argparse
1010from uuid import uuid4
11- from utils_for_filenameprocessor import get_created_at_formatted_string , move_file , invoke_filename_lambda
11+ from utils_for_filenameprocessor import get_created_at_formatted_string , move_file
1212from file_key_validation import validate_file_key , is_file_in_directory_root
1313from send_sqs_message import make_and_send_sqs_message
1414from make_and_upload_ack_file import make_and_upload_the_ack_file
15- from audit_table import upsert_audit_table , get_next_queued_file_details , ensure_file_is_not_a_duplicate
15+ from audit_table import upsert_audit_table
1616from clients import logger
1717from logging_decorator import logging_decorator
1818from supplier_permissions import validate_vaccine_type_permissions
2121 InvalidFileKeyError ,
2222 InvalidSupplierError ,
2323 UnhandledAuditTableError ,
24- DuplicateFileError ,
2524 UnhandledSqsError ,
2625)
27- from constants import FileStatus , DATA_SOURCES_BUCKET_SUFFIX , ERROR_TYPE_TO_STATUS_CODE_MAP
26+ from constants import FileStatus , ERROR_TYPE_TO_STATUS_CODE_MAP , SOURCE_BUCKET_NAME
2827
2928
3029# NOTE: logging_decorator is applied to handle_record function, rather than lambda_handler, because
@@ -47,115 +46,100 @@ def handle_record(record) -> dict:
4746 vaccine_type = "unknown"
4847 supplier = "unknown"
4948
50- if DATA_SOURCES_BUCKET_SUFFIX in bucket_name :
51-
52- # In addition to when a batch file is added to the S3 bucket root for processing, this Lambda is also invoked
53- # when the file is moved to the processing/ directory and finally the /archive directory. We want to ignore
54- # those events. Unfortunately S3 event filtering does not support triggering for root files only. See VED-781
55- # for more info.
56- if not is_file_in_directory_root (file_key ):
57- message = "Processing not required. Event was for a file moved to /archive or /processing"
58- return {"statusCode" : 200 , "message" : message , "file_key" : file_key }
59-
60- # Set default values for file-specific variables
61- message_id = "Message id was not created"
62- created_at_formatted_string = "created_at_time not identified"
63-
64- try :
65- # If the record contains a message_id, then the lambda has been invoked by a file already in the queue
66- is_existing_file = "message_id" in record
67-
68- # Get message_id if the file is not new, else assign one
69- message_id = record .get ("message_id" , str (uuid4 ()))
70-
71- created_at_formatted_string = get_created_at_formatted_string (bucket_name , file_key )
72-
73- vaccine_type , supplier = validate_file_key (file_key )
74- permissions = validate_vaccine_type_permissions (vaccine_type = vaccine_type , supplier = supplier )
75- if not is_existing_file :
76- ensure_file_is_not_a_duplicate (file_key , created_at_formatted_string )
77-
78- queue_name = f"{ supplier } _{ vaccine_type } "
79- file_status_is_queued = upsert_audit_table (
80- message_id , file_key , created_at_formatted_string , queue_name , FileStatus .PROCESSING , is_existing_file
81- )
82-
83- if file_status_is_queued :
84- message_for_logs = "File is successfully queued for processing"
85- else :
86- make_and_send_sqs_message (
87- file_key , message_id , permissions , vaccine_type , supplier , created_at_formatted_string
88- )
89- message_for_logs = "Successfully sent to SQS for further processing"
90-
91- logger .info ("Lambda invocation successful for file '%s'" , file_key )
92-
93- # Return details for logs
94- return {
95- "statusCode" : 200 ,
96- "message" : message_for_logs ,
97- "file_key" : file_key ,
98- "message_id" : message_id ,
99- "vaccine_type" : vaccine_type ,
100- "supplier" : supplier ,
101- }
49+ if bucket_name != SOURCE_BUCKET_NAME :
50+ return handle_unexpected_bucket_name (bucket_name , file_key , vaccine_type , supplier )
10251
103- except ( # pylint: disable=broad-exception-caught
104- VaccineTypePermissionsError ,
105- InvalidFileKeyError ,
106- InvalidSupplierError ,
107- UnhandledAuditTableError ,
108- DuplicateFileError ,
109- UnhandledSqsError ,
110- Exception ,
111- ) as error :
112- logger .error ("Error processing file '%s': %s" , file_key , str (error ))
113-
114- file_status = FileStatus .DUPLICATE if isinstance (error , DuplicateFileError ) else FileStatus .PROCESSED
115- queue_name = f"{ supplier } _{ vaccine_type } "
116- upsert_audit_table (
117- message_id , file_key , created_at_formatted_string , queue_name , file_status , is_existing_file
118- )
119-
120- # Create ack file
121- message_delivered = False
122- make_and_upload_the_ack_file (message_id , file_key , message_delivered , created_at_formatted_string )
123-
124- # Move file to archive
125- move_file (bucket_name , file_key , f"archive/{ file_key } " )
126-
127- # If there is another file waiting in the queue, invoke the filename lambda with the next file
128- next_queued_file_details = get_next_queued_file_details (queue_name = f"{ supplier } _{ vaccine_type } " )
129- if next_queued_file_details :
130- invoke_filename_lambda (next_queued_file_details ["filename" ], next_queued_file_details ["message_id" ])
131-
132- # Return details for logs
133- return {
134- "statusCode" : ERROR_TYPE_TO_STATUS_CODE_MAP .get (type (error ), 500 ),
135- "message" : "Infrastructure Level Response Value - Processing Error" ,
136- "file_key" : file_key ,
137- "message_id" : message_id ,
138- "error" : str (error ),
139- "vaccine_type" : vaccine_type ,
140- "supplier" : supplier
141- }
52+ # In addition to when a batch file is added to the S3 bucket root for processing, this Lambda is also invoked
53+ # when the file is moved to the processing/ directory and finally the /archive directory. We want to ignore
54+ # those events. Unfortunately S3 event filtering does not support triggering for root files only. See VED-781
55+ # for more info.
56+ if not is_file_in_directory_root (file_key ):
57+ message = "Processing not required. Event was for a file moved to /archive or /processing"
58+ return {"statusCode" : 200 , "message" : message , "file_key" : file_key }
59+
60+ # Set default values for file-specific variables
61+ message_id = "Message id was not created"
62+ created_at_formatted_string = "created_at_time not identified"
14263
143- else :
144- try :
145- vaccine_type , supplier = validate_file_key (file_key )
146- logger .error ("Unable to process file %s due to unexpected bucket name %s" , file_key , bucket_name )
147- message = f"Failed to process file due to unexpected bucket name { bucket_name } "
64+ try :
65+ message_id = str (uuid4 ())
66+ created_at_formatted_string = get_created_at_formatted_string (bucket_name , file_key )
67+
68+ vaccine_type , supplier = validate_file_key (file_key )
69+ permissions = validate_vaccine_type_permissions (vaccine_type = vaccine_type , supplier = supplier )
70+
71+ queue_name = f"{ supplier } _{ vaccine_type } "
72+ upsert_audit_table (
73+ message_id , file_key , created_at_formatted_string , queue_name , FileStatus .QUEUED
74+ )
75+ make_and_send_sqs_message (
76+ file_key , message_id , permissions , vaccine_type , supplier , created_at_formatted_string
77+ )
78+
79+ logger .info ("Lambda invocation successful for file '%s'" , file_key )
80+
81+ # Return details for logs
82+ return {
83+ "statusCode" : 200 ,
84+ "message" : "Successfully sent to SQS for further processing" ,
85+ "file_key" : file_key ,
86+ "message_id" : message_id ,
87+ "vaccine_type" : vaccine_type ,
88+ "supplier" : supplier ,
89+ }
90+
91+ except ( # pylint: disable=broad-exception-caught
92+ VaccineTypePermissionsError ,
93+ InvalidFileKeyError ,
94+ InvalidSupplierError ,
95+ UnhandledAuditTableError ,
96+ UnhandledSqsError ,
97+ Exception ,
98+ ) as error :
99+ logger .error ("Error processing file '%s': %s" , file_key , str (error ))
100+
101+ queue_name = f"{ supplier } _{ vaccine_type } "
102+ upsert_audit_table (
103+ message_id , file_key , created_at_formatted_string , queue_name , FileStatus .PROCESSED
104+ )
105+
106+ # Create ack file
107+ message_delivered = False
108+ make_and_upload_the_ack_file (message_id , file_key , message_delivered , created_at_formatted_string )
109+
110+ # Move file to archive
111+ move_file (bucket_name , file_key , f"archive/{ file_key } " )
112+
113+ # Return details for logs
114+ return {
115+ "statusCode" : ERROR_TYPE_TO_STATUS_CODE_MAP .get (type (error ), 500 ),
116+ "message" : "Infrastructure Level Response Value - Processing Error" ,
117+ "file_key" : file_key ,
118+ "message_id" : message_id ,
119+ "error" : str (error ),
120+ "vaccine_type" : vaccine_type ,
121+ "supplier" : supplier
122+ }
123+
124+
125+ def handle_unexpected_bucket_name (bucket_name : str , file_key : str , vaccine_type : str , supplier : str ) -> dict :
126+ """Handles scenario where Lambda was not invoked by the data-sources bucket. Should not occur due to terraform
127+ config and overarching design"""
128+ try :
129+ vaccine_type , supplier = validate_file_key (file_key )
130+ logger .error ("Unable to process file %s due to unexpected bucket name %s" , file_key , bucket_name )
131+ message = f"Failed to process file due to unexpected bucket name { bucket_name } "
148132
149- return {"statusCode" : 500 , "message" : message , "file_key" : file_key ,
150- "vaccine_type" : vaccine_type , "supplier" : supplier }
133+ return {"statusCode" : 500 , "message" : message , "file_key" : file_key ,
134+ "vaccine_type" : vaccine_type , "supplier" : supplier }
151135
152- except Exception as error :
153- logger .error ("Unable to process file due to unexpected bucket name %s and file key %s" ,
154- bucket_name , file_key )
155- message = f"Failed to process file due to unexpected bucket name { bucket_name } and file key { file_key } "
136+ except Exception as error :
137+ logger .error ("Unable to process file due to unexpected bucket name %s and file key %s" ,
138+ bucket_name , file_key )
139+ message = f"Failed to process file due to unexpected bucket name { bucket_name } and file key { file_key } "
156140
157- return {"statusCode" : 500 , "message" : message , "file_key" : file_key ,
158- "vaccine_type" : vaccine_type , "supplier" : supplier , "error" : str (error )}
141+ return {"statusCode" : 500 , "message" : message , "file_key" : file_key ,
142+ "vaccine_type" : vaccine_type , "supplier" : supplier , "error" : str (error )}
159143
160144
161145def lambda_handler (event : dict , context ) -> None : # pylint: disable=unused-argument
0 commit comments