Skip to content

Commit ba66324

Browse files
author
ci bot
committed
Merge branch 'feat/TG-1047-deduplicate-run-tables' into 'enterprise'
refactor(runs): deduplicate run tables against job_executions See merge request dkinternal/testgen/dataops-testgen!552
2 parents c618241 + c23fc44 commit ba66324

48 files changed

Lines changed: 422 additions & 371 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

testgen/api/runs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
)
3636
def get_test_run(job: JobExecution = resolve_job("view", JobExecution.job_key == JobKey.run_tests)): # noqa: B008
3737
"""Get a test run by the job execution ID that created it."""
38-
test_run = TestRun.get_by_id_or_job(job.id)
38+
test_run = TestRun.get(job.id)
3939

4040
result = None
4141
if test_run:
@@ -76,7 +76,7 @@ def get_test_run(job: JobExecution = resolve_job("view", JobExecution.job_key ==
7676
)
7777
def get_profiling_run(job: JobExecution = resolve_job("view", JobExecution.job_key == JobKey.run_profile)): # noqa: B008
7878
"""Get a profiling run by the job execution ID that created it."""
79-
profiling_run = ProfilingRun.get_by_id_or_job(job.id)
79+
profiling_run = ProfilingRun.get(job.id)
8080

8181
result = None
8282
if profiling_run:

testgen/commands/job_registry.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def run_final_callbacks(job_exec: JobExecution) -> None:
8080
def _notify_profiling_run(job_exec: JobExecution) -> None:
8181
with database_session() as session:
8282
profiling_run = session.scalars(
83-
select(ProfilingRun).where(ProfilingRun.job_execution_id == job_exec.id)
83+
select(ProfilingRun).where(ProfilingRun.id == job_exec.id)
8484
).first()
8585
if not profiling_run:
8686
LOG.warning("No profiling_run found for job %s; skipping notification", job_exec.id)
@@ -90,7 +90,7 @@ def _notify_profiling_run(job_exec: JobExecution) -> None:
9090

9191
def _notify_test_run(job_exec: JobExecution) -> None:
9292
with database_session() as session:
93-
test_run = session.scalars(select(TestRun).where(TestRun.job_execution_id == job_exec.id)).first()
93+
test_run = session.scalars(select(TestRun).where(TestRun.id == job_exec.id)).first()
9494
if not test_run:
9595
LOG.warning("No test_run found for job %s; skipping notification", job_exec.id)
9696
return
@@ -99,7 +99,7 @@ def _notify_test_run(job_exec: JobExecution) -> None:
9999

100100
def _notify_monitor_run(job_exec: JobExecution) -> None:
101101
with database_session() as session:
102-
test_run = session.scalars(select(TestRun).where(TestRun.job_execution_id == job_exec.id)).first()
102+
test_run = session.scalars(select(TestRun).where(TestRun.id == job_exec.id)).first()
103103
if not test_run:
104104
LOG.warning("No test_run found for job %s; skipping monitor notification", job_exec.id)
105105
return

testgen/commands/job_runner.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,12 @@ def _print_run_summary(job_id: UUID, job_key: str) -> None:
7171
session = get_current_session()
7272
match job_key:
7373
case "run-profile":
74-
run = session.scalars(select(ProfilingRun).where(ProfilingRun.job_execution_id == job_id)).first()
74+
run = session.scalars(select(ProfilingRun).where(ProfilingRun.id == job_id)).first()
7575
if run:
7676
status_msg = "Profiling encountered an error. Check log for details." if run.job_execution.status == JobStatus.ERROR else "Profiling completed."
7777
click.echo(f"\n {status_msg}\n Run ID: {run.id}\n ")
7878
case "run-tests" | "run-monitors":
79-
run = session.scalars(select(TestRun).where(TestRun.job_execution_id == job_id)).first()
79+
run = session.scalars(select(TestRun).where(TestRun.id == job_id)).first()
8080
if run:
8181
status_msg = "Test execution encountered an error. Check log for details." if run.job_execution.status == JobStatus.ERROR else "Test execution completed."
8282
click.echo(f"\n {status_msg}\n Run ID: {run.id}\n ")

testgen/commands/run_data_cleanup.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,9 @@ def run_data_cleanup(project_code: str, retention_days: int) -> None:
4242
with database_session():
4343
protected_profiling_ids = ProfilingRun.find_latest_per_table_group(project_code)
4444
protected_test_run_ids = TestRun.find_latest_per_test_suite(project_code)
45-
# Translate protected run ids → their job_execution_ids so the JE sweep
46-
# can carve them out. Nulls (older runs without a JE) are filtered here.
47-
je_map = {
48-
**ProfilingRun.get_job_execution_ids(list(protected_profiling_ids)),
49-
**TestRun.get_job_execution_ids(list(protected_test_run_ids)),
50-
}
51-
protected_job_execution_ids = {je for je in je_map.values() if je is not None}
45+
# The run id is the job execution id, so the protected run ids are
46+
# already the job executions the sweep must carve out.
47+
protected_job_execution_ids = protected_profiling_ids | protected_test_run_ids
5248

5349
LOG.info(
5450
"Protected latest runs: profiling=%d test=%d job_executions=%d",

testgen/commands/run_profiling.py

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import logging
2-
import os
32
from datetime import UTC, datetime, timedelta
43
from uuid import UUID
54

@@ -52,14 +51,12 @@ def run_profiling(
5251

5352
LOG.info("Creating profiling run record")
5453
profiling_run = ProfilingRun(
54+
id=job_context.get().job_id,
5555
project_code=table_group.project_code,
5656
connection_id=connection.connection_id,
5757
table_groups_id=table_group.id,
5858
profiling_starttime=datetime.now(UTC) + time_delta,
59-
process_id=os.getpid(),
6059
)
61-
if job_id := job_context.get().job_id:
62-
profiling_run.job_execution_id = job_id
6360

6461
# This runs in a subprocess — commit after every save so progress is visible
6562
# to the UI (separate session) and to execute_db_queries (independent connection).
@@ -96,19 +93,12 @@ def run_profiling(
9693
# run_pairwise_contingency_check(profiling_run.id, table_group.profile_pair_rule_pct)
9794
else:
9895
LOG.info("No columns were selected to profile.")
99-
except Exception as e:
96+
except Exception:
10097
LOG.exception("Profiling encountered an error.")
101-
LOG.info("Setting profiling run status to Error")
102-
profiling_run.log_message = get_exception_message(e)
103-
profiling_run.profiling_endtime = datetime.now(UTC) + time_delta
104-
profiling_run.status = "Error"
105-
profiling_run.save()
106-
session.commit()
98+
end_time = datetime.now(UTC) + time_delta
10799
raise
108100
else:
109-
LOG.info("Setting profiling run status to Completed")
110-
profiling_run.profiling_endtime = datetime.now(UTC) + time_delta
111-
profiling_run.status = "Complete"
101+
end_time = datetime.now(UTC) + time_delta
112102
profiling_run.save()
113103
session.commit()
114104

@@ -122,7 +112,7 @@ def run_profiling(
122112
sampling=table_group.profile_use_sampling,
123113
table_count=profiling_run.table_ct or 0,
124114
column_count=profiling_run.column_ct or 0,
125-
run_duration=(profiling_run.profiling_endtime - profiling_run.profiling_starttime).total_seconds(),
115+
run_duration=(end_time - profiling_run.profiling_starttime.replace(tzinfo=UTC)).total_seconds(),
126116
)
127117

128118
return profiling_run.id

testgen/commands/run_score_update.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def run_score_update(parent_job_id: str, parent_job_key: str) -> None:
3636
def _rollup_profiling(parent_je_id: UUID) -> None:
3737
with database_session() as session:
3838
profiling_run = session.scalars(
39-
select(ProfilingRun).where(ProfilingRun.job_execution_id == parent_je_id)
39+
select(ProfilingRun).where(ProfilingRun.id == parent_je_id)
4040
).first()
4141
if not profiling_run:
4242
LOG.error("No profiling_run found for job execution %s; skipping score rollup", parent_je_id)
@@ -60,7 +60,7 @@ def _rollup_test(parent_je_id: UUID) -> None:
6060
row = session.execute(
6161
select(TestRun.id, TestRun.test_starttime, TestSuite.table_groups_id, TestSuite.project_code)
6262
.join(TestSuite, TestRun.test_suite_id == TestSuite.id)
63-
.where(TestRun.job_execution_id == parent_je_id)
63+
.where(TestRun.id == parent_je_id)
6464
).first()
6565
if not row:
6666
LOG.error("No test_run found for job execution %s; skipping score rollup", parent_je_id)

testgen/commands/run_test_execution.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import logging
2-
import os
32
from collections import defaultdict
43
from datetime import UTC, datetime, timedelta
54
from functools import partial
@@ -24,7 +23,6 @@
2423
from testgen.common.models.table_group import TableGroup
2524
from testgen.common.models.test_run import TestRun
2625
from testgen.common.models.test_suite import TestSuite
27-
from testgen.utils import get_exception_message
2826

2927
from .run_refresh_data_chars import run_data_chars_refresh
3028
from .run_test_validation import run_test_validation
@@ -52,12 +50,10 @@ def run_test_execution(
5250

5351
LOG.info("Creating test run record")
5452
test_run = TestRun(
53+
id=job_context.get().job_id,
5554
test_suite_id=test_suite_id,
5655
test_starttime=datetime.now(UTC) + time_delta,
57-
process_id=os.getpid(),
5856
)
59-
if job_id := job_context.get().job_id:
60-
test_run.job_execution_id = job_id
6157

6258
# This runs in a subprocess — commit after every save so progress is visible
6359
# to the UI (separate session) and to execute_db_queries (independent connection).
@@ -134,22 +130,12 @@ def run_test_execution(
134130
# Refresh needed because previous query updates the test run too
135131
test_run.refresh()
136132

137-
except Exception as e:
133+
except Exception:
138134
LOG.exception("Test execution encountered an error.")
139-
LOG.info("Setting test run status to Error")
140-
test_run.log_message = get_exception_message(e)
141-
test_run.test_endtime = datetime.now(UTC) + time_delta
142-
test_run.status = "Error"
143-
test_run.save()
144-
session.commit()
135+
end_time = datetime.now(UTC) + time_delta
145136
raise
146137
else:
147-
LOG.info("Setting test run status to Completed")
148-
test_run.test_endtime = datetime.now(UTC) + time_delta
149-
test_run.status = "Complete"
150-
test_run.save()
151-
session.commit()
152-
138+
end_time = datetime.now(UTC) + time_delta
153139
LOG.info("Updating latest run for test suite")
154140
test_suite.last_complete_test_run_id = test_run.id
155141
test_suite.save()
@@ -167,7 +153,7 @@ def run_test_execution(
167153
username=username,
168154
sql_flavor=connection.sql_flavor_code,
169155
test_count=test_run.test_ct,
170-
run_duration=(test_run.test_endtime - test_run.test_starttime.replace(tzinfo=UTC)).total_seconds(),
156+
run_duration=(end_time - test_run.test_starttime.replace(tzinfo=UTC)).total_seconds(),
171157
prediction_duration=(datetime.now(UTC) + time_delta - prediction_start).total_seconds(),
172158
)
173159

testgen/common/models/data_column.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from testgen.common.models import get_current_session
2323
from testgen.common.models.entity import Entity, EntityMinimal
2424
from testgen.common.models.hygiene_issue import HygieneIssue
25+
from testgen.common.models.job_execution import JobExecution
2526
from testgen.common.models.profile_result import ProfileResult
2627
from testgen.common.models.profiling_run import ProfilingRun
2728

@@ -559,11 +560,11 @@ def get_column_detail(
559560
cls.dq_score_testing,
560561
func.coalesce(hygiene_subq.c.hygiene_issue_count, 0).label("hygiene_issue_count"),
561562
ProfilingRun.id.label("profile_run_id"),
562-
ProfilingRun.job_execution_id.label("profile_run_je_id"),
563-
ProfilingRun.status.label("profile_run_status"),
563+
ProfilingRun.id.label("profile_run_je_id"),
564+
JobExecution.status.label("profile_run_status"),
564565
ProfilingRun.profiling_starttime.label("profile_run_started_at"),
565-
ProfilingRun.profiling_endtime.label("profile_run_ended_at"),
566-
ProfilingRun.log_message.label("profile_run_log_message"),
566+
JobExecution.completed_at.label("profile_run_ended_at"),
567+
JobExecution.error_message.label("profile_run_log_message"),
567568
)
568569
.outerjoin(DataTable, DataTable.id == cls.table_id)
569570
.outerjoin(
@@ -585,6 +586,7 @@ def get_column_detail(
585586
),
586587
)
587588
.outerjoin(ProfilingRun, ProfilingRun.id == ProfileResult.profile_run_id)
589+
.outerjoin(JobExecution, JobExecution.id == ProfilingRun.id)
588590
.where(
589591
cls.table_groups_id == table_groups_id,
590592
cls.table_name == table_name,

testgen/common/models/data_table.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def get_profiling_overview(
134134
JobExecution.id.label("latest_profile_job_execution_id"),
135135
)
136136
.outerjoin(ProfilingRun, ProfilingRun.id == cls.last_complete_profile_run_id)
137-
.outerjoin(JobExecution, JobExecution.id == ProfilingRun.job_execution_id)
137+
.outerjoin(JobExecution, JobExecution.id == ProfilingRun.id)
138138
.where(
139139
cls.table_groups_id == table_groups_id,
140140
cls.table_name == table_name,

testgen/common/models/hygiene_issue.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ def list_for_run(
275275
ProfileResult.column_name == cls.column_name,
276276
),
277277
)
278-
.where(ProfilingRun.job_execution_id == job_execution_id, *clauses)
278+
.where(ProfilingRun.id == job_execution_id, *clauses)
279279
.order_by(cls._priority_order(), cls.table_name, cls.column_name, cls.id)
280280
)
281281
return cls._paginate(query, page=page, limit=limit, data_class=HygieneIssueListRow)
@@ -299,7 +299,7 @@ def search(
299299
cls.project_code.label("project_code"),
300300
HygieneIssueType.name.label("issue_type_name"),
301301
TableGroup.table_groups_name.label("table_groups_name"),
302-
ProfilingRun.job_execution_id.label("job_execution_id"),
302+
ProfilingRun.id.label("job_execution_id"),
303303
JobExecution.started_at.label("started_at"),
304304
cls.schema_name.label("schema_name"),
305305
cls.table_name.label("table_name"),
@@ -314,7 +314,7 @@ def search(
314314
)
315315
.join(HygieneIssueType, HygieneIssueType.id == cls.type_id)
316316
.join(ProfilingRun, ProfilingRun.id == cls.profile_run_id)
317-
.outerjoin(JobExecution, JobExecution.id == ProfilingRun.job_execution_id)
317+
.outerjoin(JobExecution, JobExecution.id == ProfilingRun.id)
318318
.join(TableGroup, TableGroup.id == cls.table_groups_id)
319319
.outerjoin(
320320
ProfileResult,
@@ -358,7 +358,7 @@ def get_with_context(cls, issue_id: UUID, *clauses) -> HygieneIssueDetail | None
358358
cls.detail.label("detail"),
359359
HygieneIssueType.detail_redactable.label("detail_redactable"),
360360
ProfileResult.pii_flag.label("pii_flag"),
361-
ProfilingRun.job_execution_id.label("job_execution_id"),
361+
ProfilingRun.id.label("job_execution_id"),
362362
JobExecution.started_at.label("started_at"),
363363
ProfileResult.general_type.label("column_general_type"),
364364
ProfileResult.db_data_type.label("column_db_data_type"),
@@ -368,7 +368,7 @@ def get_with_context(cls, issue_id: UUID, *clauses) -> HygieneIssueDetail | None
368368
)
369369
.join(HygieneIssueType, HygieneIssueType.id == cls.type_id)
370370
.join(ProfilingRun, ProfilingRun.id == cls.profile_run_id)
371-
.outerjoin(JobExecution, JobExecution.id == ProfilingRun.job_execution_id)
371+
.outerjoin(JobExecution, JobExecution.id == ProfilingRun.id)
372372
.outerjoin(
373373
ProfileResult,
374374
and_(

0 commit comments

Comments
 (0)