Bronze — Daily Incremental Load
-
Pipeline
load_bronzeruns theupdate_watermarkScript activity. It setsCONFIG.Processes.WatermarkValue=MAX(SYNCHDATE)per table fromReapit_Bronze_DWH.ODS.synchdates. This is the value the next run will filter on. Currently deactivated (state: Inactive) — the watermark is not being refreshed automatically. -
get_bronze_tablesScript activity readsSELECT * FROM CONFIG.Processes WHERE IngnoreInBronzeETL = 0. -
for_each_bronze_tableForEach iterates the returned rows sequentially. -
For each row, the source SELECT is built dynamically. The date used in the WHERE clause is
CONFIG.Processes.WatermarkValuefor that row — unless it is empty or earlier than the pipeline variablev_MinWatermarkValue(2023-09-20 17:03:14), in which case that floor is used instead. -
Query filter:
isIncremental = 1→WHERE {WatermarkField} > '{date from step 4}' AND SynchDel = 0isIncremental = 0→WHERE SynchDel = 0TableName = 'CONFIGSETTING'→ noSynchDelfilter (column does not exist)
-
land_bronzeCopy activity runs the query against Snowflake and writes to Lakehouse{TargetSchemaName}.{TableName}. -
Sink action is
OverwriteSchema. The Bronze table is dropped and recreated on every run — it holds only the rows returned by this iteration's query, not accumulated history. Persistent history lives downstream in Silver / ODS. - Loop advances to the next row; on completion the pipeline ends. Step 1's watermark refresh will run at the start of the next scheduled execution (once reactivated).
Silver — Load ODS
-
Pipeline
load_odsruns theget_notebooks_to_runScript activity:SELECT * FROM CONFIG.Processes WHERE IngnoreInSilverETL = 0. -
for_each_notebookForEach iterates the returned rows sequentially. -
For each row, a TridentNotebook activity invokes the dispatcher notebook
00_run_notebook, passingNotebookName = item().SilverNotebookName. Activity timeout: 12 hours. -
00_run_notebookcallsnotebookutils.notebook.run(NotebookName, 10800)— 180 minute timeout per notebook. -
The target merge notebook (e.g.
01_merge_lookup,03_merge_cnt) runs against theReapit_Silver_LHlakehouse. It reads the current Bronze landing tables (LANDING.*orLANDING_PP.*) usingspark.table(...), projects and reshapes the columns, and combines active / archive sources where relevant. -
The notebook then performs a Delta
MERGEinto the correspondingODS.{table}:whenMatchedUpdaterefreshes columns and setsLASTUPDATED = current_timestamp();whenNotMatchedInsertadds new rows. ODS tables are the persistent history — unlike Bronze, they are upserted, not overwritten. -
After the merge, the notebook computes
MAX(_FIVETRAN_SYNCED)per source landing table and MERGEs those values intoODS.SYNCHDATES(columnsREAPITTABLE,SYNCHDATE). This is the table Bronze'supdate_watermarkreads at the start of the next daily run. -
If the merge or synchdate update raises an exception, the notebook re-raises — the ForEach iteration fails and the pipeline moves on to the next row (no
stopOnFailure).ODS.SYNCHDATESis only updated when the corresponding merge succeeds, so a failing table cannot advance its own watermark. - Loop advances to the next row; on completion the pipeline ends.
Gold
To be documented.
End-to-end sync review
Data sync coverage
- Inserts and updates propagate. Bronze filters
WHERE {WatermarkField} > '{WatermarkValue}'(typically_FIVETRAN_SYNCED), Silver upserts into ODS on primary key. - Deletes do not propagate. Bronze filter
WHERE SynchDel = 0excludes Reapit soft-deletes. Silver MERGE only doeswhenMatchedUpdate/whenNotMatchedInsert— nowhenMatchedDelete. Fivetran-flagged deletes (_FIVETRAN_DELETED) are copied as a column but not acted on. Placeholder notebook09 Update Deleted Records - TO Doconfirms this is a known open item. - CONFIGSETTING has no
SynchDelcolumn — deletes cannot even be detected on that table. - Watermark boundary is
>not>=. Rows sharing the exact boundary timestamp could be skipped — low risk with millisecond-precision Fivetran timestamps, but not zero. - New source tables added to CONFIG without a matching Silver merge notebook will land in Bronze but never reach ODS.
Bronze → Silver → Bronze feedback loop
- Design is correct. Silver only updates
ODS.SYNCHDATESafter its MERGE succeeds (same try block, exception re-raises). Bronze'supdate_watermarkreads fromODS.SYNCHDATESat the start of the next run, so a table's watermark cannot advance past what has actually been merged. A failing Silver table stays on the old watermark and re-attempts next run. - Confirm the shortcut wiring. Silver notebooks run with default lakehouse
Reapit_Silver_LHbut callspark.table("LANDING.LOOKUP")(a Bronze schema) andDeltaTable.forName(spark, "ODS.SYNCHDATES"). Bronze'supdate_watermarkreads[Reapit_Bronze_DWH].[ODS].[synchdates]. Both references only line up ifLANDINGandODSare shortcuts inReapit_Silver_LHpointing at Bronze. A missing shortcut breaks the loop silently. Confirm via theCreate Shortcuts.Notebookin Bronze. - Currently
update_watermarkis deactivated. Bronze falls back tov_MinWatermarkValue = 2023-09-20 17:03:14, so every run pulls everything since that date. Correct but expensive — reactivate once the shortcut check above is confirmed.
SQL Endpoint / Lakehouse refresh risks
- SQL Endpoint metadata lag. Spark writes land in Delta immediately; the SQL view can lag from seconds to a few minutes. Daily schedule — not an issue. Back-to-back manual runs of Silver then Bronze — Bronze could read a stale
synchdatesand re-pull the same window (idempotent, just wasteful). Same behaviour we hit when the initial-load count check showed 12 tables and then 20 a minute later. OverwriteSchemaon Bronze drops and recreates the Delta table every run. The SQL Endpoint briefly reports "no such table" during the recreate; any downstream Power BI Import or SQL Endpoint query hitting the table during that window will hiccup. Silver reads viaspark.table()directly on Delta so it is immune.- Cross-artifact reads via SQL Endpoint (the Bronze
update_watermarkjoin toReapit_Bronze_DWH.ODS.synchdates) are the most exposed to metadata lag. For tighter chaining, run the watermark update as a Spark task inside a Silver notebook — direct Delta reads bypass the SQL Endpoint entirely. applyVOrder: falseon Bronze sink — no impact on sync, just means Delta files aren't reordered for Power BI read performance. Fine for a landing zone.- 180-minute timeout in
00_run_notebookfor Silver merges. Not a sync bug but a run-time risk on very large tables (JNL 36M rows, wide fact tables).
Recommended actions (in order)
- Fix deletes: either widen Bronze filter to include soft-deleted rows and teach Silver MERGE to
whenMatchedDeleteonSynchDel = 1/_FIVETRAN_DELETED = true, or complete notebook09 Update Deleted Recordsas a separate diff sweep. - Verify
LANDINGandODSshortcuts exist inReapit_Silver_LHbefore reactivatingupdate_watermark. - Reactivate
update_watermarkinload_bronze. - Handle CONFIGSETTING deletes with a full-diff notebook (no
SynchDelto filter on, so needs a set-difference against source). - Add a pre-flight guardrail: fail
load_odsifget_notebooks_to_runreturns a row whoseSilverNotebookNamedoes not exist as a notebook in the workspace.