Skip to content

Commit 55f7d7d

Browse files
authored
Temp table delete (#1254)
1 parent 019c899 commit 55f7d7d

6 files changed

Lines changed: 111 additions & 2 deletions

File tree

app/airflow/dags/SR_processing_dag.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@
77
process_and_create_scan_report_entries,
88
process_data_dictionary,
99
)
10-
from libs.utils import connect_to_storage, create_task, validate_params_SR_processing
10+
from libs.SR_processing.db_services import handle_failure_and_cleanup_temp_tables
11+
from libs.utils import (
12+
connect_to_storage,
13+
create_task,
14+
validate_params_SR_processing,
15+
)
1116

1217
"""
1318
This DAG automates the process of creating scan report tables, fields and values
@@ -44,6 +49,7 @@
4449
catchup=False,
4550
is_paused_upon_creation=False,
4651
dagrun_timeout=timedelta(minutes=float(AIRFLOW_DAGRUN_TIMEOUT)),
52+
on_failure_callback=handle_failure_and_cleanup_temp_tables,
4753
)
4854

4955
# TODO: add validate for DD file size: DATA_UPLOAD_MAX_MEMORY_SIZE :(

app/airflow/dags/libs/SR_processing/core.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ def process_and_create_scan_report_entries(**kwargs) -> None:
157157
logging.error(
158158
f"Error inserting tables into mapping_scanreporttable: {str(e)}"
159159
)
160+
# Clean up temp tables before updating job status to fail
161+
if table_pairs:
162+
delete_temp_tables(scan_report_id, table_pairs)
160163
update_job_status(
161164
stage=JobStageType.UPLOAD_SCAN_REPORT,
162165
status=StageStatusType.FAILED,
@@ -172,6 +175,7 @@ def process_and_create_scan_report_entries(**kwargs) -> None:
172175

173176
except Exception as e:
174177
logging.error(f"Error creating scan report fields: {str(e)}")
178+
delete_temp_tables(scan_report_id, table_pairs)
175179
update_job_status(
176180
stage=JobStageType.UPLOAD_SCAN_REPORT,
177181
status=StageStatusType.FAILED,
@@ -194,6 +198,7 @@ def process_and_create_scan_report_entries(**kwargs) -> None:
194198
)
195199
except Exception as e:
196200
logging.error(f"Error creating scan report values: {str(e)}")
201+
delete_temp_tables(scan_report_id, table_pairs)
197202
update_job_status(
198203
stage=JobStageType.UPLOAD_SCAN_REPORT,
199204
status=StageStatusType.FAILED,

app/airflow/dags/libs/SR_processing/db_services.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
import time
23
from collections import defaultdict
34
from typing import Any, Dict, List, Tuple
45

@@ -9,6 +10,7 @@
910
AIRFLOW_DAGRUN_TIMEOUT,
1011
AIRFLOW_DEBUG_MODE,
1112
EXECUTE_VALUES_PAGE_SIZE,
13+
TEMP_TABLE_CLEANUP_DELAY,
1214
)
1315
from libs.utils import update_job_status
1416
from openpyxl.worksheet.worksheet import Worksheet
@@ -238,3 +240,91 @@ def delete_temp_tables(scan_report_id: int, table_pairs: List[Tuple[str, int]])
238240
except Exception as e:
239241
logging.error(f"Error deleting temporary tables: {str(e)}")
240242
raise e
243+
244+
245+
def cleanup_temp_tables_for_scan_report(scan_report_id: int) -> List[Tuple[str, int]]:
246+
"""
247+
Clean up temporary tables for a scan report.
248+
249+
Deletes temporary tables (temp_data_dictionary and temp_field_values) for all tables
250+
associated with the given scan_report_id in mapping_scanreporttable.
251+
252+
Returns:
253+
List of (table_name, table_id) tuples for the tables that were cleaned up.
254+
"""
255+
256+
query = """
257+
SELECT name, id
258+
FROM mapping_scanreporttable
259+
WHERE scan_report_id = %(scan_report_id)s
260+
"""
261+
records = pg_hook.get_records(query, parameters={"scan_report_id": scan_report_id})
262+
table_pairs = [(record[0], record[1]) for record in records] if records else []
263+
if table_pairs:
264+
delete_temp_tables(scan_report_id, table_pairs)
265+
return table_pairs
266+
267+
268+
def handle_failure_and_cleanup_temp_tables(context):
269+
"""
270+
Delete temporary tables when the DAG fails or times out.
271+
272+
This handles cleanup when failures happen outside the normal pipeline code, like
273+
timeouts or external errors. Since the tables are already in the database even if
274+
the DAG fails, we query mapping_scanreporttable to find all tables for this
275+
scan_report_id, then delete the temp tables (temp_data_dictionary and
276+
temp_field_values).
277+
278+
When a timeout occurs, the task that was running may still be creating temporary tables in the background.
279+
This function waits TEMP_TABLE_CLEANUP_DELAY seconds first so any in-flight table creation can finish,
280+
then runs a single cleanup pass. Cleanup is not urgent, so waiting once is simpler than cleaning twice.
281+
282+
283+
Args:
284+
context: Airflow execution context containing task_instance, dag, dag_run, etc.
285+
"""
286+
try:
287+
dag_run = context["dag_run"]
288+
dag = context.get("dag")
289+
dag_run_conf = dag_run.conf or {}
290+
scan_report_id = dag_run_conf.get("scan_report_id")
291+
292+
if not scan_report_id:
293+
logging.warning(
294+
"No scan_report_id found in DAG run configuration, skipping temp table cleanup"
295+
)
296+
return
297+
298+
# Update job status to FAILED for scan_report_processing DAG
299+
if dag and dag.dag_id == "scan_report_processing":
300+
try:
301+
update_job_status(
302+
stage=JobStageType.UPLOAD_SCAN_REPORT,
303+
status=StageStatusType.FAILED,
304+
scan_report=scan_report_id,
305+
details="Scan report processing DAG timed out or failed.",
306+
)
307+
logging.info(
308+
"Updated job status to FAILED for scan_report_id=%s",
309+
scan_report_id,
310+
)
311+
except Exception as e:
312+
logging.error("Failed to update job status on failure: %s", str(e))
313+
314+
# Wait so a timed-out task can finish creating tables, then delete the temporary tables
315+
delay = TEMP_TABLE_CLEANUP_DELAY
316+
time.sleep(delay)
317+
318+
table_pairs = cleanup_temp_tables_for_scan_report(scan_report_id)
319+
if table_pairs:
320+
logging.info(
321+
"Deleted temp tables for scan_report_id=%s (n=%d)",
322+
scan_report_id,
323+
len(table_pairs),
324+
)
325+
logging.info(
326+
"Completed temp table cleanup for scan_report_id=%s", scan_report_id
327+
)
328+
329+
except Exception as e:
330+
logging.error("Failed to delete temporary tables on failure: %s", str(e))

app/airflow/dags/libs/settings.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717
# Timedelta for dagrun_timeout in minutes
1818
AIRFLOW_DAGRUN_TIMEOUT = os.getenv("AIRFLOW_DAGRUN_TIMEOUT", 60)
1919

20+
# In failure callback, temp table cleanup is performed twice.
21+
# This delay (seconds) gives the timed-out task time to finish creating tables.
22+
TEMP_TABLE_CLEANUP_DELAY = int(os.getenv("TEMP_TABLE_CLEANUP_DELAY", "60"))
23+
2024
# Page size for bulk database inserts (execute_values)
21-
EXECUTE_VALUES_PAGE_SIZE = int(os.getenv("EXECUTE_VALUES_PAGE_SIZE", 10000))
25+
EXECUTE_VALUES_PAGE_SIZE = int(os.getenv("EXECUTE_VALUES_PAGE_SIZE", 1000000))
2226

2327
AIRFLOW_VAR_JSON_VERSION = os.getenv("AIRFLOW_VAR_JSON_VERSION", "v1")

app/airflow/dags/libs/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import ast
22
import json
33
import logging
4+
import time
45
from typing import Any, Dict, List, Optional, TypedDict
56

67
from airflow.models.connection import Connection
@@ -158,6 +159,7 @@ def update_job_status_on_failure(context):
158159
Args:
159160
context: Airflow execution context containing task_instance, dag, dag_run, etc.
160161
"""
162+
logging.info("update_job_status_on_failure callback triggered")
161163
try:
162164
# Extract information from Airflow context
163165
task_instance = context["task_instance"]

docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,9 @@ services:
200200
# Search recommendations feature flag - controls whether search recommendations task is included in auto_mapping DAG
201201
SEARCH_ENABLED: False
202202
AIRFLOW_DAGRUN_TIMEOUT: 60 # Timeout for each dagrun in minutes
203+
TEMP_TABLE_CLEANUP_DELAY: 60 # delay between cleanup attempts on failure
203204
AIRFLOW_VAR_JSON_VERSION: v2
205+
EXECUTE_VALUES_PAGE_SIZE: 1000000 # page size for bulk database inserts (execute_values)
204206

205207
volumes:
206208
db_data:

0 commit comments

Comments
 (0)