Skip to content

Commit b6456cd

Browse files
committed
Java SDK: answer a task handler parse with every handler
The parse request no longer names Dags, and the Dag processor reuses an artifact's answer for every Dag file that uses the artifact, so the answer must not depend on what was asked. The vendored schema is resynced in the same commit because the request model generated from it no longer has dag_ids.
1 parent fc8f15c commit b6456cd

7 files changed

Lines changed: 28 additions & 53 deletions

File tree

‎airflow-core/tests/unit/dag_processing/test_task_handler_processor_java.py‎

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,6 @@ def test_a_built_bundle_declares_its_task_handlers(example_bundle):
162162
bundle_path=example_bundle,
163163
bundle_name="java-task-handlers",
164164
artifact_rel_path=jar.name,
165-
dag_ids=[
166-
"java_xcom_casting_example",
167-
"java_interface_example",
168-
"java_annotation_example",
169-
"java_native_interface_example",
170-
"not_registered",
171-
],
172165
logger=structlog.get_logger(),
173166
)
174167

@@ -207,9 +200,9 @@ def test_a_built_bundle_declares_its_task_handlers(example_bundle):
207200
},
208201
)
209202
assert list(result.task_handlers) == [
210-
"java_xcom_casting_example",
211203
"java_interface_example",
212204
"java_annotation_example",
205+
"java_xcom_casting_example",
213206
]
214207
with zipfile.ZipFile(jar) as zf:
215208
manifest = _parse_manifest(zf.read("META-INF/MANIFEST.MF"))

‎java-sdk/README.md‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -677,8 +677,7 @@ launches the JVM application as a subprocess. The flow is:
677677
The Dag processor also launches each JAR to ask which task handlers it
678678
registers. The first frame is then a `TaskHandlerParseRequest`, and
679679
`execution/TaskHandlerParse.kt` replies with one `TaskHandlerParsingResult`:
680-
the task-handler registrations of the requested Dags, each with its binding
681-
mode and parameters. Flat data parameters bind `positional` and a `TaskInput`
680+
every task-handler registration, each with its binding mode and parameters. Flat data parameters bind `positional` and a `TaskInput`
682681
binds `named`. The annotation processor records a handler's parameter names on
683682
its generated task class (`internal/TaskParams.kt`), because Java does not keep
684683
them at run time. The JVM waits for the reply's acknowledgement, then exits.

‎java-sdk/sdk/schema/schema.json‎

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4199,19 +4199,12 @@
41994199
"type": "object"
42004200
},
42014201
"TaskHandlerParseRequest": {
4202-
"description": "Request for Task Handler Parsing.\n\nAsks a Lang-SDK runtime which task handlers an artifact registers for the given Dags.",
4202+
"description": "Request for Task Handler Parsing.\n\nAsks a Lang-SDK runtime for every task handler an artifact registers.",
42034203
"properties": {
42044204
"file": {
42054205
"title": "File",
42064206
"type": "string"
42074207
},
4208-
"dag_ids": {
4209-
"items": {
4210-
"type": "string"
4211-
},
4212-
"title": "Dag Ids",
4213-
"type": "array"
4214-
},
42154208
"bundle_path": {
42164209
"format": "path",
42174210
"title": "Bundle Path",
@@ -4230,15 +4223,14 @@
42304223
},
42314224
"required": [
42324225
"file",
4233-
"dag_ids",
42344226
"bundle_path",
42354227
"bundle_name"
42364228
],
42374229
"title": "TaskHandlerParseRequest",
42384230
"type": "object"
42394231
},
42404232
"TaskHandlerParsingResult": {
4241-
"description": "Result of Task Handler Parsing.\n\nThe task handlers a Lang-SDK artifact registers, keyed by Dag id.",
4233+
"description": "Result of Task Handler Parsing.\n\nEvery task handler a Lang-SDK artifact registers, keyed by Dag id.\n\nThe answer depends only on the artifact, never on the request.",
42424234
"properties": {
42434235
"fileloc": {
42444236
"title": "Fileloc",

‎java-sdk/sdk/src/main/kotlin/org/apache/airflow/sdk/Server.kt‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,8 @@ class ApiError(
7373
* execution requests to the registered [Bundle].
7474
*
7575
* The Dag processor starts the same entry point to ask which task handlers
76-
* the bundle registers. That process replies with the handlers registered for
77-
* the requested Dags and how each binds its arguments, runs no task, and
78-
* exits.
76+
* the bundle registers. That process replies with every registered handler
77+
* and how each binds its arguments, runs no task, and exits.
7978
*
8079
* The typical entry point is:
8180
*

‎java-sdk/sdk/src/main/kotlin/org/apache/airflow/sdk/execution/TaskHandlerParse.kt‎

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,29 +36,23 @@ import java.lang.reflect.Modifier
3636
import java.lang.reflect.Type
3737

3838
/**
39-
* Answers a [TaskHandlerParseRequest] with the task handlers [bundle]
40-
* registers for the requested Dags, as a TaskHandlerParsingResult body.
39+
* Answers a [TaskHandlerParseRequest] with every task handler [bundle]
40+
* registers, keyed by Dag id in registration order, as a
41+
* TaskHandlerParsingResult body.
4142
*
4243
* Only task-handler registrations count: a Dag declared in Java is its own,
43-
* not a Python Dag's. A requested Dag with no handlers is left out. The
44-
* generated models cannot hold `task_handlers`, so the body is a map.
44+
* not a Python Dag's. The generated models cannot hold `task_handlers`, so
45+
* the body is a map.
4546
*/
4647
internal fun parseTaskHandlers(
4748
bundle: Bundle,
4849
request: TaskHandlerParseRequest,
49-
): Map<String, Any?> {
50-
val declarations = linkedMapOf<String, List<Map<String, Any?>>>()
51-
for (dagId in request.dagIds) {
52-
if (dagId in declarations) continue
53-
val dag = bundle.taskHandlers[dagId] ?: continue
54-
declarations[dagId] = dag.tasks.values.map(::declare)
55-
}
56-
return linkedMapOf(
50+
): Map<String, Any?> =
51+
linkedMapOf(
5752
"type" to "TaskHandlerParsingResult",
5853
"fileloc" to request.file,
59-
"task_handlers" to declarations,
54+
"task_handlers" to bundle.taskHandlers.mapValues { (_, dag) -> dag.tasks.values.map(::declare) },
6055
)
61-
}
6256

6357
private fun declare(task: TaskDef): Map<String, Any?> {
6458
val (binding, params) = bindingOf(task.definition)

‎java-sdk/sdk/src/test/kotlin/org/apache/airflow/sdk/ServerTest.kt‎

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ class ServerTest {
135135
val supervisor =
136136
Thread {
137137
runBlocking {
138-
toServer.writeFrame(taskHandlerParseRequestFrame(3, "/bundle/etl.jar", listOf("etl")))
138+
toServer.writeFrame(taskHandlerParseRequestFrame(3, "/bundle/etl.jar"))
139139
val prefix = fromServer.readByteArray(4)
140140
val raw = Frame.decodeRaw(ArrayBufferInput(fromServer.readByteArray(Frame.parseLengthPrefix(prefix).toInt())))
141141
reported.put(raw)
@@ -169,7 +169,7 @@ class ServerTest {
169169
val supervisor =
170170
Thread {
171171
runBlocking {
172-
toServer.writeFrame(taskHandlerParseRequestFrame(3, "/bundle/etl.jar", listOf("etl")))
172+
toServer.writeFrame(taskHandlerParseRequestFrame(3, "/bundle/etl.jar"))
173173
val prefix = fromServer.readByteArray(4)
174174
fromServer.readByteArray(Frame.parseLengthPrefix(prefix).toInt())
175175
toServer.close()
@@ -187,17 +187,14 @@ class ServerTest {
187187
private fun taskHandlerParseRequestFrame(
188188
id: Int,
189189
file: String,
190-
dagIds: List<String>,
191190
): ByteArray {
192191
val out = ByteArrayOutputStream()
193192
MessagePack.newDefaultPacker(out).use { packer ->
194193
packer.packArrayHeader(2)
195194
packer.packInt(id)
196-
packer.packMapHeader(5)
195+
packer.packMapHeader(4)
197196
packer.packString("type").packString("TaskHandlerParseRequest")
198197
packer.packString("file").packString(file)
199-
packer.packString("dag_ids").packArrayHeader(dagIds.size)
200-
dagIds.forEach { packer.packString(it) }
201198
packer.packString("bundle_path").packString("/bundle")
202199
packer.packString("bundle_name").packString("java-task-handlers")
203200
}

‎java-sdk/sdk/src/test/kotlin/org/apache/airflow/sdk/execution/TaskHandlerParseTest.kt‎

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,9 @@ private class Audit : Task {
109109
) = Unit
110110
}
111111

112-
private fun request(vararg dagIds: String) =
112+
private fun request() =
113113
TaskHandlerParseRequest().apply {
114114
file = "/bundles/java/etl.jar"
115-
this.dagIds = dagIds.toList()
116115
bundlePath = "/bundles/java"
117116
bundleName = "java-task-handlers"
118117
}
@@ -151,8 +150,8 @@ private fun assertConforms(
151150

152151
class TaskHandlerParseTest {
153152
@Test
154-
@DisplayName("Should declare each requested Dag's task handlers in registration order")
155-
fun declaresRequestedDagsInRegistrationOrder() {
153+
@DisplayName("Should declare every task handler in registration order")
154+
fun declaresEveryTaskHandlerInRegistrationOrder() {
156155
val bundle =
157156
Bundle()
158157
.register("etl", "extract", GeneratedFlat::class.java)
@@ -163,7 +162,7 @@ class TaskHandlerParseTest {
163162
.register("report", "audit", Audit::class.java)
164163
.register(DagDef("native").addTask("audit", Audit::class.java))
165164

166-
val result = parseTaskHandlers(bundle, request("etl", "native", "missing", "etl"))
165+
val result = parseTaskHandlers(bundle, request())
167166

168167
val regions =
169168
mapOf("anyOf" to listOf(mapOf("type" to "array", "items" to NULLABLE_STRING), mapOf("type" to "null")))
@@ -189,9 +188,11 @@ class TaskHandlerParseTest {
189188
mapOf("task_id" to "audit", "binding" to "named", "params" to emptyList<Any>()),
190189
mapOf("task_id" to "notify", "binding" to "named", "params" to emptyList<Any>()),
191190
),
191+
"report" to listOf(mapOf("task_id" to "audit", "binding" to "named", "params" to emptyList<Any>())),
192192
),
193193
)
194194
assertEquals(expected, result)
195+
assertEquals(listOf("etl", "report"), (result["task_handlers"] as Map<*, *>).keys.toList())
195196
}
196197

197198
@Test
@@ -203,7 +204,7 @@ class TaskHandlerParseTest {
203204
.register("etl", "score", GeneratedInput::class.java)
204205
.register("etl", "audit", Audit::class.java)
205206

206-
val result = parseTaskHandlers(bundle, request("etl"))
207+
val result = parseTaskHandlers(bundle, request())
207208

208209
assertConforms("TaskHandlerParsingResult", result)
209210
val bindings =
@@ -221,11 +222,11 @@ class TaskHandlerParseTest {
221222
}
222223

223224
@Test
224-
@DisplayName("Should send an empty map when no requested Dag has task handlers")
225-
fun sendsEmptyTaskHandlersWhenNothingMatches() {
226-
val bundle = Bundle().register("etl", "audit", Audit::class.java)
225+
@DisplayName("Should send an empty map when the bundle registers no task handler")
226+
fun sendsEmptyTaskHandlersWithoutHandlers() {
227+
val bundle = Bundle().register(DagDef("native").addTask("audit", Audit::class.java))
227228

228-
val result = parseTaskHandlers(bundle, request("other"))
229+
val result = parseTaskHandlers(bundle, request())
229230

230231
assertEquals(emptyMap<String, Any?>(), result["task_handlers"])
231232
}

0 commit comments

Comments
 (0)