This is an automated email from the ASF dual-hosted git repository.

jason810496 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 27f8b682234 Add a Language SDK spec to the Task SDK docs (#72765)
27f8b682234 is described below

commit 27f8b6822341f27dbb066de42de2cda16a03d7f0
Author: Jason(Zhe-You) Liu <[email protected]>
AuthorDate: Thu Sep 17 10:43:09 2026 +0800

    Add a Language SDK spec to the Task SDK docs (#72765)
    
    * Add a Language SDK spec to the Task SDK docs
    
    Three Lang SDKs are designing their user-facing authoring interfaces at
    once, and each was settling the same questions inside its own ADR: what
    separates a task handler from a native Dag, what to call the thing that
    holds either of them, and where a task body gets its context and client.
    Naming those once, somewhere every SDK's docs can point at, means a Go,
    Java, or TypeScript author reads about the same concepts under different
    spellings rather than three unrelated vocabularies.
    
    * Rename StubHandler to StubTask in the Language SDK spec
    
    The name should say what the SDK registers, and what it registers is a
    task: Python declares it with @task.stub, gives it a task_id, and the SDK
    supplies only its body. "Handler" described the callable rather than the
    thing it stands for, leaving these docs using a word no other part of
    Airflow uses for a task.
    
    * Rename StubTask to TaskHandler in the Language SDK spec
    
    Python declares the task; an SDK supplies only its body. Naming the SDK
    object after the task overloads a word the native surface already uses for
    something the user creates with dag.Task, so it names the role the SDK
    actually plays instead.
---
 task-sdk/docs/index.rst         |   1 +
 task-sdk/docs/lang-sdk-spec.rst | 167 ++++++++++++++++++++++++++++++++++++++++
 task-sdk/docs/lang-sdk.rst      |  42 ++++++++++
 3 files changed, 210 insertions(+)

diff --git a/task-sdk/docs/index.rst b/task-sdk/docs/index.rst
index 9a125a316b5..8e0c005b047 100644
--- a/task-sdk/docs/index.rst
+++ b/task-sdk/docs/index.rst
@@ -178,5 +178,6 @@ For the full public API reference, see the :doc:`api` page.
   resumable-job-mixin
   api
   concepts
+  lang-sdk
   executable-bundle-spec
   ts-bundle-spec
diff --git a/task-sdk/docs/lang-sdk-spec.rst b/task-sdk/docs/lang-sdk-spec.rst
new file mode 100644
index 00000000000..fed3c2d6f15
--- /dev/null
+++ b/task-sdk/docs/lang-sdk-spec.rst
@@ -0,0 +1,167 @@
+ .. Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+ ..   http://www.apache.org/licenses/LICENSE-2.0
+
+ .. Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+
+Language SDK Spec
+=================
+
+This document fixes the terms an Airflow Language SDK (Go, Java, TypeScript, 
...) uses for
+its user-facing authoring interface, and how they fit together. Every SDK 
spells them in its
+own language's idiom; the terms and the flow are the same everywhere.
+
+Spec version: ``1.0``.
+
+There are two authoring features, and they differ in one thing: who owns the 
graph.
+
+.. code-block:: text
+
+     FEATURE 1                                   FEATURE 2
+     Mixed Language Task Handler                 Native Dag
+     Python owns the graph                       the SDK owns the graph
+
+     Python @task.stub                           Dag(spec)
+     declares dag_id, task_id,                          |
+     arguments, and every edge                          v
+           |                                           dag  <-- owns the 
schedule,
+           | binds by dag_id + task_id                  |        the tasks, 
the edges
+           v                                            v
+     fn --> TaskHandler(dagId, taskId, fn)       fn --> dag.Task(fn, options)
+                    |                                           |
+                    v                                           v
+             TaskHandlerRef                                  TaskRef
+                    |                                           |
+                    |                                           |  Inputs(ref) 
     data edge, carries a value
+                    |                                           |  before / 
after   order edge, carries nothing
+                    |                                           v
+                    |                                        TaskRef
+                    |                                           |
+                    +---------------------+---------------------+
+                                          |
+                                          v
+                         bundle.register(Dag | TaskHandler)
+                                          |
+                                          v
+                                   bundle.serve()  <-- the task subprocess 
entrypoint
+
+A ``TaskHandler`` supplies a body for a task Python already declared, so it 
names the
+``dagId``/``taskId`` pair it binds to and nothing else. A native ``Dag`` owns 
the schedule, the
+tasks, and the edges, so ``dag.Task`` returns a ``TaskRef`` that edges attach 
to. Both features
+land in the same ``bundle``, and one ``bundle.serve()`` call serves both, so a 
single process can carry
+native Dags and mixed-language task handlers at once.
+
+Terms
+-----
+
+.. list-table::
+   :header-rows: 1
+   :widths: 22 78
+
+   * - Term
+     - Definition
+   * - ``fn``
+     - The function callable itself: the task body a user writes.
+   * - ``TaskHandler``
+     - Callable interface factory over ``(dagId, taskId, fn)``; returns a 
``TaskHandlerRef``.
+   * - ``Dag``
+     - Callable interface factory over a Dag spec; returns a ``DagRef``.
+   * - ``dag``
+     - The instance a ``Dag`` call returns.
+   * - ``dag.Task``
+     - Callable interface factory over ``(fn, options)``; returns a 
``TaskRef``.
+   * - ``bundle``
+     - Holds every ``Dag`` and ``TaskHandler``. One ``register`` takes either 
kind, in any
+       mixture, and the bundle serves them.
+   * - ``serve``
+     - A method on the ``bundle``: the task subprocess's entrypoint calls 
``bundle.serve()``,
+       which serves it for the lifetime of the process. Nothing outside the 
``bundle`` needs a
+       handle on the serving machinery.
+
+Per-SDK spelling
+----------------
+
+.. list-table::
+   :header-rows: 1
+   :widths: 16 28 28 28
+
+   * - Term
+     - Go
+     - Java
+     - TypeScript
+   * - ``fn``
+     - a ``func``
+     - an annotated method, or an ``InputTask``
+     - an ``async`` function
+   * - ``TaskHandler``
+     - ``airflow.TaskHandler(dagId, taskId, fn)``
+     - ``@Builder.TaskHandler(dagId, taskId)``
+     - ``new TaskHandler(dagId, taskId, fn)``
+   * - ``Dag``
+     - ``airflow.Dag(spec)``
+     - ``@Builder.Dag(id, ...)``, or ``new Dag(id)``
+     - ``new Dag(id)``
+   * - ``dag``
+     - ``*airflow.DagRef``
+     - ``Dag``
+     - ``Dag``
+   * - ``dag.Task``
+     - ``dag.Task(fn, opts...)``
+     - ``@Builder.Task(id)``, or ``dag.task(id, cls)``
+     - ``dag.task(id, fn)``
+   * - data edge
+     - ``airflow.Inputs(refs...)``
+     - the ``@Wiring`` call expression
+     - the task factory call
+   * - order edge
+     - ``Before`` / ``After``
+     - ``before`` / ``after``
+     - ``before`` / ``after``
+   * - ``bundle``
+     - ``airflow.Bundle()`` -> ``*airflow.BundleRef``
+     - ``new Bundle()``
+     - ``new Bundle()``
+   * - ``register``
+     - ``bundle.Register(items ...airflow.Registration)``
+     - ``bundle.register(dag, handler, ...)``
+     - ``bundle.register(dag, handler, ...)``
+   * - ``serve``
+     - ``bundle.Serve()`` in ``main``
+     - ``bundle.serve(args)`` in ``main``
+     - ``await bundle.serve()`` in the entry module
+
+Task subprocess lifecycle
+-------------------------
+
+Authoring is only half the contract. Every SDK runs the same sequence inside 
the task
+subprocess, once per task instance:
+
+.. code-block:: text
+
+   1  process start
+   2  receive StartupDetails from the supervisor
+   3  build Context + Client, bind the cancellation signal
+   4  look up the registered fn for (dag_id, task_id)
+   5  bind arguments: TaskFlow data, plus ctx/client where they are injected
+   6  +-- scope holding Context + Client --+
+      |             invoke fn              |   <-- a getter reads this scope
+      +------------------------------------+
+   7  push the return value to XCom, report the terminal state
+
+Steps 2 through 5 and step 7 belong to the SDK; step 6 is the only one that 
runs code a user
+wrote. How ``fn`` reaches ``Context`` and ``Client`` is each SDK's own choice 
— parameters, or
+getters that read the scope opened at step 6 — and all this spec asks is that 
``fn`` receives the
+same pair the SDK built at step 3. The terminal state at step 7 is one of 
``SucceedTask``,
+``RetryTask``, or ``TaskState``, and it is reported exactly once.
diff --git a/task-sdk/docs/lang-sdk.rst b/task-sdk/docs/lang-sdk.rst
new file mode 100644
index 00000000000..6e0061d2ef8
--- /dev/null
+++ b/task-sdk/docs/lang-sdk.rst
@@ -0,0 +1,42 @@
+ .. Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+ ..   http://www.apache.org/licenses/LICENSE-2.0
+
+ .. Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+
+Non-Python SDKs
+===============
+
+Airflow tasks can be written in languages other than Python through a Language 
SDK
+(Go, Java, TypeScript, ...). These pages specify what every such SDK shares. 
For the
+user-facing guides, see 
:doc:`apache-airflow:authoring-and-scheduling/language-sdks/index`.
+
+For all programming languages
+-----------------------------
+
+.. toctree::
+   :maxdepth: 1
+
+   lang-sdk-spec
+
+Compiled programming languages
+------------------------------
+
+An SDK that produces a binary artifact also has to agree on the shape of that 
artifact.
+
+.. toctree::
+   :maxdepth: 1
+
+   executable-bundle-spec

Reply via email to