Commit 9a0e965
fix: get_latest_materialization_event returns stale pre-wipe materialization (#25511)
## Summary & Motivation
Fixes
[#15806](#15806):
`instance.get_latest_materialization_event` returned a stale, wiped
materialization after `dagster asset wipe`, instead of `None` as
documented. Also fixes the Dagster Plus analogue of the bug for
partition wipes (reported by a cloud customer).
Asset wipes are soft deletes: `wipe_asset` records a wipe timestamp on
the `asset_keys` row, and readers treat the asset as live when
`last_materialization_timestamp > wipe_timestamp`. The problem is that
`ASSET_MATERIALIZATION_PLANNED` and `ASSET_OBSERVATION` events also bump
`last_materialization_timestamp` (intentionally, so planned/observed
assets show in the catalog) without updating the cached
`last_materialization` record — which `wipe_asset` never cleared. So the
moment any new run targeting a wiped asset started (or an observation
was reported), the row passed the wipe filter and
`_get_latest_materialization_records` returned the stale pre-wipe
record. A post-wipe observation resurfaced the stale materialization
indefinitely. This also affected `get_asset_records`
(`AssetRecord.asset_entry.last_materialization_record`) and
`get_latest_materialization_code_versions`, which share the same path.
### OSS fixes (`SqlEventLogStorage`)
- **Write side:** `wipe_asset` now also nulls out
`last_materialization`, so newly wiped rows are self-consistent. (This
matches what the Plus event log storage has always done.)
- **Read side:** `_get_latest_materialization_records` only trusts the
cached record when its timestamp postdates the wipe; otherwise it falls
back to the backcompat event-log query, which now has
`_add_assets_wipe_filter_to_query` applied. This covers rows wiped by
older Dagster versions where the stale blob is already in the database,
and also fixes the same latent staleness for legacy old-format rows that
always took the backcompat path.
- **Legacy visibility path:** `_fetch_backcompat_materialization_times`
(used by the pre-`ASSET_KEY_INDEX_COLS`-migration read path to decide
whether a wiped asset is live) now only counts
materialization/observation/planned events, mirroring what bumps
`last_materialization_timestamp` on the migrated path. Previously it
took `max(timestamp)` over *all* events, so the `ASSET_WIPED` event
stored by `instance.wipe_assets` immediately after the wipe made the
wiped asset appear live in `all_asset_keys`. This was latent until the
write-side fix above stopped the stale blob from short-circuiting that
path — it broke `TestAssetWipe::test_asset_wipe` in the postgres graphql
CI jobs, whose fixture creates tables via alembic without marking the
secondary index (postgres gates `last_materialization_timestamp` writes
on that index, so those storages stay on the legacy path forever).
### Plus fix (`HostCloudEventLogStorage`)
Full-asset wipes already clear `last_materialization`, but
`wipe_asset_partitions` deleted the per-partition materialization rows
while leaving the cached `last_materialization` on the asset row
untouched. If the latest materialization belonged to a wiped partition,
`get_latest_materialization_events` / `get_asset_records` kept returning
it. The partition wipe now recomputes the cached record from the
remaining materializations when it points at a wiped partition (falling
back to `None` when none remain). The cached-value read locks the
`asset_keys` row (`FOR UPDATE`) through the recompute, so a
materialization committing mid-wipe either lands before the recompute
reads (and is included) or after the wipe commits (and overwrites with
the newer value) — the recomputed value can never clobber a newer
concurrent materialization. The lock is acquired in the same order as
the store path (`asset_keys` last), so it adds no deadlock risk. Note
the adjacent caches (`last_observation`,
`last_failed_to_materialize_event`, `last_skipped_materialize_event`)
have the same staleness after partition wipes and are left for
follow-up.
## Test Plan
- Extended the shared-suite `test_asset_wipe`: after a wipe, a planned
event and then an observation must not resurface the old materialization
from `get_latest_materialization_events` or `get_asset_records`, and a
re-materialization must surface the new event. Runs against sqlite,
consolidated sqlite, in-memory, legacy, postgres, mysql, and the Plus
storages (host cloud, archive-aware, ursula graphql).
- Extended the shared-suite `test_asset_partitioned_wiped_event` (Plus
storages only): wiping the latest-materialized partition falls back to
the latest remaining materialization, wiping a non-latest partition
leaves it untouched, and wiping the only remaining partition clears it.
Verified to fail without the Plus fix.
- New
`test_get_latest_materialization_ignores_stale_cached_row_after_wipe`
(sqlite) simulates a row wiped by an older version (stale cached record
restored via direct SQL after the wipe) to exercise the read-side guard.
Verified to fail without the read-side fix.
- New `test_all_asset_keys_excludes_wiped_asset_on_legacy_index_path`
(dagster-postgres) simulates the unmigrated-index condition from the
graphql CI fixture and reproduces the exact `assert AssetKey(...) not in
[AssetKey(...)]` failure from build 155619 without the legacy-path fix;
passes with it.
- Locally green: `dagster_tests/storage_tests/test_event_log.py` (519
passed), `dagster_postgres_tests/test_event_log.py` (142 passed), the
previously-failing `TestAssetWipe` postgres graphql variants,
cloud-backend `test_event_log_storage.py` +
`test_archive_aware_storage.py` via tox (553 passed), and the ursula
graphql storage wipe tests.
## Changelog
Fixed a bug where `DagsterInstance.get_latest_materialization_event`
(and `get_asset_records`) could return a stale pre-wipe materialization
for a wiped asset once a new run targeting the asset started or an
observation was reported. In Dagster+, fixed the analogous bug where
wiping partitions could leave the wiped partition's materialization as
the asset's latest materialization.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Internal-RevId: d05abfe7d759123142e63f4d191113e3aab529f21 parent 8c85005 commit 9a0e965
4 files changed
Lines changed: 248 additions & 24 deletions
File tree
- python_modules
- dagster
- dagster_tests/storage_tests
- utils
- dagster/_core/storage/event_log
- libraries/dagster-postgres/dagster_postgres_tests
Lines changed: 50 additions & 23 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1164 | 1164 | | |
1165 | 1165 | | |
1166 | 1166 | | |
1167 | | - | |
| 1167 | + | |
| 1168 | + | |
1168 | 1169 | | |
1169 | 1170 | | |
1170 | 1171 | | |
1171 | 1172 | | |
1172 | 1173 | | |
| 1174 | + | |
| 1175 | + | |
1173 | 1176 | | |
1174 | 1177 | | |
1175 | 1178 | | |
1176 | 1179 | | |
1177 | 1180 | | |
1178 | | - | |
| 1181 | + | |
| 1182 | + | |
| 1183 | + | |
| 1184 | + | |
1179 | 1185 | | |
1180 | 1186 | | |
1181 | | - | |
1182 | | - | |
1183 | | - | |
1184 | | - | |
1185 | | - | |
1186 | | - | |
1187 | | - | |
1188 | | - | |
1189 | | - | |
1190 | | - | |
1191 | | - | |
1192 | | - | |
1193 | | - | |
1194 | | - | |
1195 | | - | |
1196 | | - | |
1197 | | - | |
| 1187 | + | |
| 1188 | + | |
| 1189 | + | |
| 1190 | + | |
| 1191 | + | |
| 1192 | + | |
| 1193 | + | |
| 1194 | + | |
| 1195 | + | |
| 1196 | + | |
| 1197 | + | |
| 1198 | + | |
| 1199 | + | |
| 1200 | + | |
| 1201 | + | |
| 1202 | + | |
| 1203 | + | |
| 1204 | + | |
| 1205 | + | |
1198 | 1206 | | |
1199 | | - | |
| 1207 | + | |
| 1208 | + | |
| 1209 | + | |
| 1210 | + | |
| 1211 | + | |
| 1212 | + | |
| 1213 | + | |
| 1214 | + | |
1200 | 1215 | | |
1201 | 1216 | | |
1202 | 1217 | | |
| |||
1527 | 1542 | | |
1528 | 1543 | | |
1529 | 1544 | | |
1530 | | - | |
| 1545 | + | |
| 1546 | + | |
| 1547 | + | |
1531 | 1548 | | |
1532 | 1549 | | |
1533 | 1550 | | |
| |||
1536 | 1553 | | |
1537 | 1554 | | |
1538 | 1555 | | |
1539 | | - | |
1540 | | - | |
| 1556 | + | |
| 1557 | + | |
| 1558 | + | |
| 1559 | + | |
| 1560 | + | |
| 1561 | + | |
| 1562 | + | |
| 1563 | + | |
| 1564 | + | |
| 1565 | + | |
| 1566 | + | |
1541 | 1567 | | |
1542 | 1568 | | |
1543 | 1569 | | |
| |||
1758 | 1784 | | |
1759 | 1785 | | |
1760 | 1786 | | |
| 1787 | + | |
1761 | 1788 | | |
1762 | 1789 | | |
1763 | 1790 | | |
| |||
Lines changed: 59 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
16 | 23 | | |
17 | 24 | | |
18 | 25 | | |
19 | 26 | | |
20 | 27 | | |
21 | 28 | | |
22 | 29 | | |
| 30 | + | |
23 | 31 | | |
24 | 32 | | |
25 | 33 | | |
| |||
31 | 39 | | |
32 | 40 | | |
33 | 41 | | |
| 42 | + | |
34 | 43 | | |
35 | 44 | | |
36 | 45 | | |
37 | 46 | | |
38 | 47 | | |
39 | 48 | | |
40 | 49 | | |
| 50 | + | |
41 | 51 | | |
42 | 52 | | |
43 | 53 | | |
| |||
218 | 228 | | |
219 | 229 | | |
220 | 230 | | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
221 | 279 | | |
222 | 280 | | |
223 | 281 | | |
| |||
Lines changed: 77 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2923 | 2923 | | |
2924 | 2924 | | |
2925 | 2925 | | |
| 2926 | + | |
| 2927 | + | |
| 2928 | + | |
| 2929 | + | |
| 2930 | + | |
| 2931 | + | |
| 2932 | + | |
| 2933 | + | |
| 2934 | + | |
| 2935 | + | |
| 2936 | + | |
| 2937 | + | |
| 2938 | + | |
| 2939 | + | |
| 2940 | + | |
| 2941 | + | |
| 2942 | + | |
| 2943 | + | |
| 2944 | + | |
| 2945 | + | |
| 2946 | + | |
| 2947 | + | |
| 2948 | + | |
| 2949 | + | |
| 2950 | + | |
| 2951 | + | |
| 2952 | + | |
| 2953 | + | |
| 2954 | + | |
| 2955 | + | |
| 2956 | + | |
| 2957 | + | |
| 2958 | + | |
| 2959 | + | |
| 2960 | + | |
| 2961 | + | |
| 2962 | + | |
| 2963 | + | |
| 2964 | + | |
| 2965 | + | |
| 2966 | + | |
| 2967 | + | |
| 2968 | + | |
| 2969 | + | |
| 2970 | + | |
| 2971 | + | |
| 2972 | + | |
| 2973 | + | |
| 2974 | + | |
| 2975 | + | |
| 2976 | + | |
| 2977 | + | |
| 2978 | + | |
| 2979 | + | |
| 2980 | + | |
2926 | 2981 | | |
2927 | 2982 | | |
2928 | 2983 | | |
| |||
2969 | 3024 | | |
2970 | 3025 | | |
2971 | 3026 | | |
| 3027 | + | |
| 3028 | + | |
| 3029 | + | |
| 3030 | + | |
| 3031 | + | |
| 3032 | + | |
| 3033 | + | |
| 3034 | + | |
| 3035 | + | |
| 3036 | + | |
| 3037 | + | |
| 3038 | + | |
| 3039 | + | |
| 3040 | + | |
| 3041 | + | |
| 3042 | + | |
| 3043 | + | |
| 3044 | + | |
| 3045 | + | |
| 3046 | + | |
| 3047 | + | |
| 3048 | + | |
2972 | 3049 | | |
2973 | 3050 | | |
2974 | 3051 | | |
| |||
Lines changed: 62 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
7 | 15 | | |
| 16 | + | |
| 17 | + | |
8 | 18 | | |
9 | 19 | | |
10 | 20 | | |
| |||
140 | 150 | | |
141 | 151 | | |
142 | 152 | | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
0 commit comments