Fix deadline callback data encoding in migration 0094 (scheduler CrashLoopBackOff)#69985
Open
seanmuth wants to merge 3 commits into
Open
Fix deadline callback data encoding in migration 0094 (scheduler CrashLoopBackOff)#69985seanmuth wants to merge 3 commits into
seanmuth wants to merge 3 commits into
Conversation
Migration 0094 (replace_deadline_inline_callback_with_fkey) moves inline
deadline callbacks into the callback table, whose data column is ExtendedJSON
(read back via BaseSerialization.deserialize). Both upgrade paths built the
callback data without recursively extended-serializing the callback kwargs:
- Postgres: json_build_object wrapped only the top level, embedding the old
kwargs jsonb raw.
- MySQL/SQLite: wrote the callback dict with no extended wrapping at all.
Any callback whose kwargs contain a nested dict (e.g. metric tags) is then
unreadable -- BaseSerialization.deserialize raises KeyError('__var') and the
scheduler enters CrashLoopBackOff on the deadline-processing loop.
Both upgrade paths now extended-serialize the callback data (a recursive
pg_temp SQL function for the Postgres CTE, a _serialize_extended helper for
the Python path), and the downgrade paths decode kwargs back to raw so an
upgrade/downgrade round-trip is preserved. Deployments already upgraded across
0094 must repair existing callback.data rows out of band.
Closes: apache#69980
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #69980.
What's the problem
Migration
0094_3_2_0_replace_deadline_inline_callback_with_fkeymoves inline deadline callbacks into thecallbacktable, whosedatacolumn isExtendedJSON— read back at runtime viaBaseSerialization.deserialize, which requires every nested dict to be wrapped as{"__type": "dict", "__var": {...}}.Both upgrade paths built
callback.datawithout recursively extended-serializing the callbackkwargs:_upgrade_postgresql):json_build_objectwrapped only the top level, embedding the old callback'skwargsjsonb raw._upgrade_mysql_sqlite): wrote the callback dict via a plainJSONcolumn with no extended wrapping at all.So any callback whose
kwargscontain a nested dict (e.g. metrictags) is stored unreadable. When the scheduler loads it in the deadline-processing loop,BaseSerialization.deserializerecurses into the outerdictnode, hits the bare nested object, runsencoded_var[Encoding.VAR], and raisesKeyError(<Encoding.VAR: '__var'>)— crashing the scheduler on every loop (CrashLoopBackOff), before it heartbeats, with no OOM and no other logged exception.What's in this PR
BaseSerialization.serialize:pg_temp.encode_extended(jsonb)function used inside the existing batch CTE (keeps the one-round-trip design)._serialize_extended()helper applied to the callback dict.kwargsback to raw (pg_temp.decode_extended/_deserialize_extended), so an upgrade→downgrade round-trip is preserved. Both decoders are lenient, so they also correctly downgrade data written by the pre-fix version of this migration.test_0094_deadline_callback_migration.py): existing assertions now verifycallback.dataround-trips through the realBaseSerialization; added a nested-kwargs/tagsregression test and an encode/decode helper round-trip test.Already-affected deployments
This hotfix protects deployments that have not yet run
0094. Deployments already upgraded across0094with nested-dict callback kwargs have latent corruptcallback.datarows (a scheduler crash that fires when such a deadline becomes due); those rows must be repaired out of band — e.g. re-encode the affected rows:🤖 Opened with Claude Code (model: Claude Opus 4.8,
claude-opus-4-8[1m]).