Repository navigation
Java SDK: answer TaskHandlerParseRequest with registered handlers - #73977
Merged
jason810496 merged 0 commit intoOct 5, 2026
Conversation
jason810496
added this pull request to stack #73978
September 30, 2026 17:59
This was referenced Sep 30, 2026
jason810496
force-pushed
the
jason/core-taskhandler-refactor/08-java-sdk-task-handler-parse
branch
from
October 1, 2026 06:26
782aeda to
d6ba5da
Compare
jason810496
force-pushed
the
jason/core-taskhandler-refactor/08-java-sdk-task-handler-parse
branch
from
October 1, 2026 06:30
d6ba5da to
58e6a8c
Compare
jason810496
force-pushed
the
jason/core-taskhandler-refactor/08-java-sdk-task-handler-parse
branch
from
October 1, 2026 10:55
58e6a8c to
03405f9
Compare
This was referenced Oct 1, 2026
jason810496
force-pushed
the
jason/core-taskhandler-refactor/08-java-sdk-task-handler-parse
branch
2 times, most recently
from
October 2, 2026 00:54
b6456cd to
949c919
Compare
jason810496
force-pushed
the
jason/core-taskhandler-refactor/08-java-sdk-task-handler-parse
branch
from
October 2, 2026 05:48
949c919 to
f508e20
Compare
1 task done
jason810496
force-pushed
the
jason/core-taskhandler-refactor/08-java-sdk-task-handler-parse
branch
from
October 2, 2026 11:36
f508e20 to
f599ee6
Compare
This was referenced Oct 3, 2026
jason810496
deleted the
jason/core-taskhandler-refactor/08-java-sdk-task-handler-parse
branch
October 5, 2026 18:12
jason810496
force-pushed
the
jason/core-taskhandler-refactor/08-java-sdk-task-handler-parse
branch
from
October 5, 2026 18:12
f599ee6 to
94a8e22
Compare
jason810496
restored the
jason/core-taskhandler-refactor/08-java-sdk-task-handler-parse
branch
October 6, 2026 02:34
Member
Author
|
This was not really merged. The stack was reordered so the TypeScript layer now sits on top of this Java layer, and once both branches were pushed, this PR's commits were already in its base branch, so GitHub marked it merged automatically and deleted its head branch. No merge commit was made. The Java layer continues in #74317, in the new stack #74318. |
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), on native #74037 (stack #74170): #73973, #73974, #73975, #73977, #73976, #74067, #74135, #74140, #74141, #73971, #74030, #74031, #74032, #74136, #74137, #74138, #74139
Why
The Dag processor will check each stub task against the task handler that the artifact a worker would run registers (ADR-0011, ADR-0012). #73974 added the probe and the coordinator hooks, and #73975 made Go bundles answer. Today a Java bundle fails on a
TaskHandlerParseRequestas an unexpected first frame.This PR makes a Java bundle answer with every handler registered through
@Builder.TaskHandlerorBundle.register(dagId, taskId, cls)and how each handler's parameters bind. It also letsJavaCoordinatorfind the JAR a stub task would run and start it for the probe. Nothing calls the probe yet: #74135 does.What changes
A Java bundle registers task handlers as before:
When the Dag processor probes it, the bundle replies with every task handler it registers, keyed by Dag id.
task_handlersdepends only on the JAR, never on the request, andfilelocrepeats the request'sfile.Java runtime
@Builder.TaskHandlerclasses andBundle.register(dagId, taskId, cls)are declared, in registration order, and no handler runs. The tasks of a Dag declared in Java (DagDef,@Builder.Dag) are never task handlers, so the reply leaves them out. A test pins this, and theServerKDoc says so.@Builder.Dagtask with@GeneratedDagTask, andBundle.register(dagId, taskId, cls)rejects such a class. Its task belongs to a Dag declared in Java, so the error tells the author to declare a task handler with@Builder.TaskHandler. A test fails without the check, and theBundle.registerKDoc andjava-sdk/README.mdsay so.positional, with their Java names. ATaskInput(as the only data parameter, or as anInputTask<I>) isnamed, and@ArgNamefields match exactly. A handler that reads no argument isnamedwith no params, so the Dag processor only warns about an argument passed to it.-parameters. So the annotation processor gives each class it generates for a@Builder.TaskHandlermethod a staticAIRFLOW_TASK_PARAMSfield with its flat parameters' names and declared types, or itsTaskInputtype.@Builder.Dagtask classes get no such field.value_schemais the declared Java type in the vocabularybuild_arg_bindingsemits for a Python annotation:{"type": "object"}without its fields;String, the boxed numbers,BigInteger,BigDecimal,UUID,Durationand thejava.timedate and time types (OffsetDateTime,ZonedDateTime,LocalDateTime,Instant,LocalDate,LocalTime) each get a schema;byte[],Object,Optional,Date,URIand thejava.timetypes not listed above (such asOffsetTimeandPeriod) get none;Class.getFieldshas no defined order;"5"into along), as pydantic's schemas do for its lax mode.task_handlers, so the reply is a plain map. An SDK test checks its keys, required fields and binding values against the vendored supervisor schema.Vendored supervisor schema
java-sdk/sdk/schema/schema.jsonwas refreshed only when itsapi_versionchanged, by downloading the published file. A version is published only at release, so the in-progress2026-10-30returns 404 and messages added during the cycle never reached the Java models.:sdk:syncSupervisorSchemanow copies the Task SDK snapshot when it declares the configured version. It downloads the published file as before otherwise.schema.json, and the snapshot is copied only withjava-sdk/gradlew -p java-sdk :sdk:syncSupervisorSchema, then commit the file. No build step runs the task, so a later change to the Task SDK snapshot neither rewrites the file nor failsktlint. A read-only:sdk:checkSupervisorSchemaVersionfails generation when the file is not at the configured version.DagSourceCode,UpdateDagRunNote,retry_reason,multi_teamand more required fields). It also dropsmap_indexandelement_indexfromXComArgBinding, which the Task SDK snapshot never declared;ArgBinding.ktstill reads them from the raw map, so decoding does not change. The Java SDK and its tests need no other change.sync-java-sdk-supervisor-schemahook stays a version-only check at the pre-commit stage and runs the task only when the configured version changes. Only the hook's docstring and prek description changed.Coordinator
JavaCoordinator._find_task_handler_artifact(bundle_path=..., dag_id=...)is the worker's own scan (_JarInfo.find,main_classincluded), so the Dag processor checks the JAR a worker would run. The Dag id plays no part, because a task of any Dag runs the same Main-Class.airflow-sdkJAR that gives a thin JAR its schema version, so_JarInfonow records the path. A caller computes the path in the Dag bundle relative tobundle_path.resolve().JavaCoordinator._build_parse_task_handler_command(path=...)is a task's own command, so the probe answers for the classpath and Main-Class a worker would run. Withoutmain_classthat is the scan's pick (Coordinator: detect ambiguous entrypoints and duplicate dag_ids at import time #71134).2026-10-30, and the Java SDK reports it.2026-10-30but cannot answer, so its probe fails. Check stub tasks against task handlers when a Dag file is parsed #74135 then logs a warning, and rebuilding the bundle fixes it.Bundles
The example, the e2e test bundle, the Scala Spark example and the k8s example registered the Java tasks of Python-owned Dags as a Dag declared in Java, which the reply never reports. They now register those tasks as task handlers. Execution already falls back to task handlers, so runs do not change.
Docs
30_new_language_sdk.rst) saysJavaCoordinatorimplements both hooks.java-sdk/README.mddescribes the parse and the rejection of a@Builder.Dagtask class. A task of a Python Dag is a@Builder.TaskHandleror a hand-writtenTaskclass registered withBundle.register(dagId, taskId, cls).Builds on #73974 (hooks,
parse_task_handler, the gate, the probe) and #73973 (the models), and on native #74036 (_build_command,_JarInfowith its sorted walk,read_main_attributes). No user docs: #74135 adds them.How to test
Ran:
java-sdk/gradlew -p java-sdk build --rerun-taskspassed with 202 tests against 190 before (processor 24, sdk 150, jpl 10, jul 6, log4j2 5, slf4j 7).:sdk:checkSupervisorSchemaVersionpasses (api_version=2026-10-30), the build leavesschema.jsonuntouched, andcmpshows it identical to the monorepo snapshot.ktlint,spotlessand sync hooks,java-sdkand both schemas, after adding a$defsentry to the snapshot at the sameapi_version:prek run ktlint --all-filesfailed withfiles were modifiedbefore this change, because the build copied the snapshot overschema.json. Now all three hooks pass with--all-files, a Gradle build leaves the file untouched, andjava-sdk/gradlew -p java-sdk :sdk:syncSupervisorSchemacopies the snapshot when asked. When the configured version and the snapshot move together, a build fails on the check and names that command, and the sync hook refreshes the file.coordinators/: 412 passed, run serially.java/test_coordinator.pygoes from 57 to 74 tests:TestMainJar(3 new, 5 updated),TestFindTaskHandlerArtifact(8) andTestBuildParseTaskHandlerCommand(6, including the probe exec).dag_processing/: 747 passed, 10 skipped (the 8 that need a backend, the FAB auth manager or the system test Dags, and the two real probes without their variable).AIRFLOW_LANG_SDK_REAL_PROBE_TESTS=1: 1 passed in 18 s with a warm Gradle cache, on JDK 11. It findsprobe-example.jar(theairflow-sdkJAR beside it sets the schema version) and the probe answers with the three Dags that register task handlers. The nativejava_native_interface_exampleDag is left out.main_classthe scan stops onjavassist.CtClass, because five dependency JARs set a Main-Class, so such a bundle needsmain_class. With it set, the find returnscompile-scala.jarand the probe answersscala_spark_examplewithspark_extract,spark_transformandspark_load, eachnamedwith no params.BuilderProcessor.ktfails 11 processor tests: three for the handler params field and eight for the marker. Dropping only the marker fails the eight.Bundle.registerfailsshouldRejectClassGeneratedForDagTask.ValueSchemaTestdoes not compile withoutValueSchema.kt, and dropping.sorted()fails the scalar test.Server.ktfails both Server parse tests, the second on its check of the error (Unexpected initial frameinstead ofCoordinator comm closed), not on a timeout. Adding the Dags of the bundle to the reply fails twoTaskHandlerParseTesttests and the Server answer test. Renamingexact_namefails the schema check, and swallowing the missing acknowledgement failsfailsTaskHandlerParseWithoutAcknowledgement._build_jar_commandfails the two-JARs test, and scanning the directory of the found JAR instead of the scan roots fails theapp/andlibs/layout test.Server.ktthe real probe returns no handlers andThe Lang-SDK runtime exited with code 1 without a parse result. With the old coordinator the find raisesNotImplementedError, and with the old examplejava_interface_exampleis missing.prekover the whole range at the pre-commit stage passed withlychee-dockerandregenerate-java-sdk-verification-metadataskipped (66 hooks passed, the rest had no files to check, includingcheck-supervisor-schemas-versions). The Task SDK schema,airflow-core/src, the Go and TS SDKs and the Gradle plugin are untouched.mypy-task-sdk,mypy-airflow-core,mypy-scriptsand the sync hook pass with--all-files.Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Opus 5.5) following the guidelines