fix(dags): build stg_gias_ukprn monthly, never daily (review)
Rebuilding the view in the daily build dropped the Ofsted views on it (CASCADE), which dim_school reads: every daily run would have failed. A selector test now rejects any build that drops views it then reads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cfc9367bb3
commit
c16dd0044f
3 files changed
+43
-2
No files matched your search
@@ -111,7 +111,7 @@ print(f'Validation passed: {{count}} GIAS rows')
|
|||||||
# where that DAG hasn't run (pipeline/tests/test_dag_selectors.py).
|
# where that DAG hasn't run (pipeline/tests/test_dag_selectors.py).
|
||||||
dbt_build = BashOperator(
|
dbt_build = BashOperator(
|
||||||
task_id="dbt_build",
|
task_id="dbt_build",
|
||||||
bash_command=f"cd {PIPELINE_DIR}/transform && {DBT_BIN} build --profiles-dir . --target production --select stg_gias_establishments+ stg_gias_links+ gias_code_names+ stg_gias_ukprn --exclude int_ks2_with_lineage+ int_ks4_with_lineage+ stg_ees_ks4_destinations+ stg_ees_ks5_destinations+",
|
bash_command=f"cd {PIPELINE_DIR}/transform && {DBT_BIN} build --profiles-dir . --target production --select stg_gias_establishments+ stg_gias_links+ gias_code_names+ --exclude int_ks2_with_lineage+ int_ks4_with_lineage+ stg_ees_ks4_destinations+ stg_ees_ks5_destinations+",
|
||||||
)
|
)
|
||||||
|
|
||||||
sync_typesense = BashOperator(
|
sync_typesense = BashOperator(
|
||||||
@@ -146,7 +146,7 @@ with DAG(
|
|||||||
|
|
||||||
dbt_build_ofsted = BashOperator(
|
dbt_build_ofsted = BashOperator(
|
||||||
task_id="dbt_build",
|
task_id="dbt_build",
|
||||||
bash_command=f"cd {PIPELINE_DIR}/transform && {DBT_BIN} build --profiles-dir . --target production --select stg_ofsted_inspections+ stg_ofsted_fe_providers+ stg_ofsted_fe_inspections+ int_ofsted_latest+ fact_ofsted_inspection+ dim_school+ --exclude stg_ees_ks4_destinations+ stg_ees_ks5_destinations+",
|
bash_command=f"cd {PIPELINE_DIR}/transform && {DBT_BIN} build --profiles-dir . --target production --select stg_ofsted_inspections+ stg_ofsted_fe_providers+ stg_ofsted_fe_inspections+ stg_gias_ukprn+ int_ofsted_latest+ fact_ofsted_inspection+ dim_school+ --exclude stg_ees_ks4_destinations+ stg_ees_ks5_destinations+",
|
||||||
)
|
)
|
||||||
|
|
||||||
sync_typesense_ofsted = BashOperator(
|
sync_typesense_ofsted = BashOperator(
|
||||||
|
|||||||
@@ -96,3 +96,41 @@ def test_selected_models_only_read_models_that_exist(dag_id):
|
|||||||
missing = {model: sorted(PARENTS[model] - available) for model in sorted(selected)
|
missing = {model: sorted(PARENTS[model] - available) for model in sorted(selected)
|
||||||
if PARENTS[model] - available}
|
if PARENTS[model] - available}
|
||||||
assert missing == {}, f'{dag_id} builds models whose parents it never builds: {missing}'
|
assert missing == {}, f'{dag_id} builds models whose parents it never builds: {missing}'
|
||||||
|
|
||||||
|
|
||||||
|
TABLE = re.compile(r"materialized\s*=\s*['\"]table['\"]")
|
||||||
|
|
||||||
|
|
||||||
|
def views():
|
||||||
|
"""Staging and intermediate models are views unless configured as tables."""
|
||||||
|
out = set()
|
||||||
|
for path in MODELS.rglob('*.sql'):
|
||||||
|
layer = path.relative_to(MODELS).parts[0]
|
||||||
|
if layer in ('staging', 'intermediate') and not TABLE.search(path.read_text()):
|
||||||
|
out.add(path.stem)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
VIEWS = views()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('dag_id', sorted(BUILDS))
|
||||||
|
def test_rebuilt_relations_do_not_drop_views_the_build_reads(dag_id):
|
||||||
|
"""dbt rebuilds a relation by dropping the old one with CASCADE, which drops
|
||||||
|
every view built on it. A view dropped that way and not rebuilt by the same
|
||||||
|
build is gone when that build reads it: the daily GIAS build rebuilt
|
||||||
|
stg_gias_ukprn and dropped the Ofsted views dim_school reads (audit H4)."""
|
||||||
|
selected = selected_models(BUILDS[dag_id], PARENTS)
|
||||||
|
children = defaultdict(set)
|
||||||
|
for model, ps in PARENTS.items():
|
||||||
|
for p in ps:
|
||||||
|
children[p].add(model)
|
||||||
|
dropped, stack = set(), list(selected)
|
||||||
|
while stack:
|
||||||
|
for child in children[stack.pop()]:
|
||||||
|
if child in VIEWS and child not in dropped:
|
||||||
|
dropped.add(child)
|
||||||
|
stack.append(child)
|
||||||
|
dropped -= selected
|
||||||
|
broken = {m: sorted(PARENTS[m] & dropped) for m in sorted(selected) if PARENTS[m] & dropped}
|
||||||
|
assert broken == {}, f'{dag_id} drops views it then reads: {broken}'
|
||||||
@@ -3,6 +3,9 @@
|
|||||||
-- A model on the raw source rather than a column of stg_gias_establishments:
|
-- A model on the raw source rather than a column of stg_gias_establishments:
|
||||||
-- a ref to that model would put the Ofsted models into the daily build's
|
-- a ref to that model would put the Ofsted models into the daily build's
|
||||||
-- stg_gias_establishments+ selection (pipeline/tests/test_dag_selectors.py).
|
-- stg_gias_establishments+ selection (pipeline/tests/test_dag_selectors.py).
|
||||||
|
-- Built by the monthly Ofsted DAG with the views on it, never by the daily
|
||||||
|
-- one: rebuilding a view drops the views on it (CASCADE), and dim_school, which
|
||||||
|
-- the daily build makes, reads int_ofsted_latest and int_ofsted_listed.
|
||||||
|
|
||||||
select
|
select
|
||||||
cast("URN" as integer) as urn,
|
cast("URN" as integer) as urn,
|
||||||
|
|||||||
Reference in new issue
Block a user