Repository navigation
Find Lang-SDK task handler artifacts and decide which to probe - #74032
Draft
jason810496 wants to merge 6 commits into
Conversation
jason810496
added this pull request to stack #73978
October 1, 2026 13:34
This was referenced Oct 1, 2026
This was referenced Oct 1, 2026
jason810496
force-pushed
the
jason/core-taskhandler-refactor/10-task-handler-bindings-reconcile
branch
from
October 1, 2026 14:44
568fa9f to
fead951
Compare
jason810496
force-pushed
the
jason/core-taskhandler-refactor/11-candidate-listing-fast-path
branch
from
October 1, 2026 14:44
4392e00 to
efd9eb0
Compare
jason810496
force-pushed
the
jason/core-taskhandler-refactor/10-task-handler-bindings-reconcile
branch
from
October 2, 2026 00:54
fead951 to
a937384
Compare
jason810496
force-pushed
the
jason/core-taskhandler-refactor/11-candidate-listing-fast-path
branch
from
October 2, 2026 00:54
efd9eb0 to
3e03718
Compare
jason810496
force-pushed
the
jason/core-taskhandler-refactor/10-task-handler-bindings-reconcile
branch
from
October 2, 2026 05:48
a937384 to
391143b
Compare
jason810496
force-pushed
the
jason/core-taskhandler-refactor/11-candidate-listing-fast-path
branch
from
October 2, 2026 05:48
3e03718 to
1c5b1ca
Compare
1 task done
jason810496
force-pushed
the
jason/core-taskhandler-refactor/10-task-handler-bindings-reconcile
branch
from
October 2, 2026 11:36
391143b to
dc3fd66
Compare
jason810496
force-pushed
the
jason/core-taskhandler-refactor/11-candidate-listing-fast-path
branch
from
October 2, 2026 11:36
1c5b1ca to
19e73b5
Compare
The Dag processor must find the task-handler artifacts in a coordinator's Dag bundle before it can ask them anything, and only the coordinator knows which files are its artifacts. A hook next to the command hooks lets each SDK say so, together with the fingerprint an artifact stores, without running or hashing it.
The AFBNDL01 trailer is what marks a file as a Go bundle, so the Dag processor lists by it and not by the executable bit. An object-store Dag bundle drops that bit, and such a bundle used to be silently skipped; it is now listed with an error the Dag processor can report. The stored cache digest is read from the metadata region without hashing the binary.
A Java bundle also holds its dependency JARs, and some of them declare Main-Class (five of six in the Scala Spark example), so Main-Class cannot tell a handler JAR apart. The Airflow-Cache-Digest attribute that the Gradle plugin writes can, and it is the fingerprint the Dag processor compares. A JAR that carries it without Main-Class cannot be run, so it is listed with an error rather than skipped.
The Dag processor needs a fingerprint it can compare on every parse without hashing a bundle. A TS bundle's layout line already records the SHA-256 of every region, so hashing that one line changes whenever the bundle does and stays stable across packs of the same inputs. A .min.mjs file is listed as a task handler bundle only when its first line carries the layout marker, since any minified module may carry that suffix. One whose layout line is invalid is listed with an error, so the Dag processor can report the broken bundle instead of a missing handler.
Probing an artifact starts a subprocess, and every Dag file is re-parsed every 30 seconds by default, so a parse must reuse a recorded answer whenever it still holds. Because a probe now asks for every handler, its answer depends only on the artifact, and the size plus stored cache digest it was recorded with is a sound key for every Dag file, not only the one that probed. The decision is a pure function, so the wiring in _parse_file can use it without a database.
The ADR still described the fast path that compared each Dag file's stored params and required an unchanged candidate set, which was unsound across files. With the whole answer recorded per artifact, a candidate is skipped when its own fingerprint matches, a new artifact is probed by the first file that lists it, and Java JARs are recognised by their cache digest rather than by Main-Class.
jason810496
force-pushed
the
jason/core-taskhandler-refactor/11-candidate-listing-fast-path
branch
from
October 2, 2026 14:57
19e73b5 to
d238a18
Compare
jason810496
force-pushed
the
jason/core-taskhandler-refactor/10-task-handler-bindings-reconcile
branch
from
October 2, 2026 14:57
dc3fd66 to
aa3f771
Compare
This was referenced Oct 3, 2026
jason810496
removed this pull request from stack #73978
October 6, 2026 02:27
1 task done
This branch has not been deployed
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.
Stack (bottom to top): #73970, #73971, #73972, #73973, #73974, #73975, #73976, #73977, #74030, #74031, #74032, #74033, #74067
Why
The Dag-file parse will resolve each
@task.stubtask against the artifacts in its coordinator's Dag bundle (ADR-0013 Flow 1, steps 4 and 5). To do that it must find the artifacts without running them, and skip the probe subprocess for an artifact whose recorded answer still holds. This PR adds both. Nothing calls them yet; a later PR wires them into_parse_file.What changes
BaseCoordinator.list_task_handler_candidates(bundle_path)raisesNotImplementedErrorby default.SubprocessCoordinatorwalks the bundle in sorted order and asks a new per-language hook,_read_task_handler_candidate(path, *, rel_path), about each file. A file reached through symlinks is listed once, under the first path walked, and a coordinator without the hook raisesNotImplementedErrorbefore walking. The hook reads what marks the artifact and its stored digest, takes the size from the same open file, and never hashes the artifact.AFBNDL01trailer, whatever its executable bit. A bundle without the bit, or with a trailer this runtime cannot run, is listed with anerror. Object-store Dag bundles drop the bit, and such a bundle used to be skipped silently..jarwhose manifest carriesAirflow-Cache-Digest. In the Scala Spark example bundle, 6 of 167 JARs declareMain-Class, 5 of them dependencies, and only the bundle JAR carries the digest. A digest JAR withoutMain-Classis listed with anerror. A JAR whose manifest cannot be read (an encrypted entry, an unsupported compression, corrupt LZMA data) is skipped, like any other unreadable JAR..min.mjswhose first line starts with the//# airflowBundle=marker. One whose layout line is invalid is listed with anerror. A.min.mjswithout the marker may be an unrelated minified module, so it is skipped.read_cache_digestnow shares its reader with the listing. The new TSread_cache_digestis the SHA-256 of the whole layout line, which records every region's SHA-256, sohead -n1 bundle.min.mjs | sha256sumreproduces it. Java reads the manifest attribute. A stored digest says "unchanged", not "intact", so the size is compared too, and execution's integrity check is unchanged. A digest longer than 128 characters, the column's length, becomesNone, so that artifact is probed on every parse.plan_task_handler_probesdecides each candidate on its own, with no database:erroris rejected, even when a recorded answer matches it;ts-bundle-spec.rst, one sentence each in theJavaCoordinatorandExecutableCoordinatordocstrings, and ADR-0013's fast path, Flow 1 steps 4 to 8 and Consequences, plus the Java marker in ADR-0014.How to test
Ran:
test_coordinator.pytests: 299 passed.dag_processingsuite on SQLite: 680 passed, 13 skipped (the opt-in real probes and a Postgres/MySQL-only lock test).bundle-v1.min.mjsone, whose digest equalshead -n1 | sha256sum.mypy-task-sdkandmypy-airflow-coreon all files, and theprekpre-commit hooks on the changed files, passed.Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Opus 5.5) following the guidelines