@@ -33,14 +33,17 @@ runtime used to execute registered TypeScript handlers from Airflow.
3333## Task Handlers
3434
3535``` ts
36- import { registerTask , type TaskHandlerArgs } from " @apache-airflow/ts-sdk" ;
36+ import { Dag , DagRegistry , serveDags , type TaskHandlerArgs } from " @apache-airflow/ts-sdk" ;
3737
3838export async function sayHello({ ctx , client }: TaskHandlerArgs ) {
3939 const greeting = await client .getVariable (" greeting" );
4040 return { message: ` Hello from ${ctx .taskId }: ${greeting } ` };
4141}
4242
43- registerTask ({ dagId: " example_dag" , taskId: " say_hello" }, sayHello );
43+ const dag = new Dag (" example_dag" );
44+ dag .task (" say_hello" , sayHello );
45+
46+ await serveDags (new DagRegistry (dag ));
4447```
4548
4649Non-` undefined ` return values are pushed to XCom under the ` "return_value" `
@@ -95,7 +98,7 @@ Airflow metadata in the bundle itself.
9598TypeScript entrypoint:
9699
97100``` ts
98- import { registerTask , startCoordinator , type TaskHandlerArgs } from " @apache-airflow/ts-sdk" ;
101+ import { Dag , DagRegistry , serveDags , type TaskHandlerArgs } from " @apache-airflow/ts-sdk" ;
99102
100103export async function extract({ client }: TaskHandlerArgs ) {
101104 const connection = await client .getConnection (" sales_db" );
@@ -118,33 +121,49 @@ export async function transform({ client }: TaskHandlerArgs) {
118121 };
119122}
120123
121- registerTask ({ dagId: " sales_pipeline" , taskId: " extract" }, extract );
122- registerTask ({ dagId: " sales_pipeline" , taskId: " transform" }, transform );
124+ const salesPipeline = new Dag (" sales_pipeline" );
125+ salesPipeline .task (" extract" , extract );
126+ salesPipeline .task (" transform" , transform );
123127
124- await startCoordinator ( );
128+ await serveDags ( new DagRegistry ( salesPipeline ) );
125129```
126130
127131The Python stub defines the Dag dependency graph. The TypeScript handler does
128- the work and uses ` TaskClient ` for task-time Airflow data access. Register each
129- handler with the Python Dag's ` dag_id ` and the stub task's ` task_id ` . The
130- handler function is the reusable task implementation; ` registerTask ` binds that
131- handler to a Python stub Dag/task identity for coordinator mode.
132+ the work and uses ` TaskClient ` for task-time Airflow data access. Create a
133+ ` Dag ` with the Python Dag's ` dag_id ` and attach each handler with the stub
134+ task's ` task_id ` . The handler function is the reusable task implementation;
135+ ` dag.task ` binds that handler to a Python stub task identity, a ` DagRegistry `
136+ collects the Dags this bundle can execute, and ` serveDags ` serves them to
137+ Airflow.
138+
139+ ` serveDags ` is the entrypoint, and the registry it is given is the whole bundle:
140+ a Dag left out of the registry is not part of the bundle, and its tasks are
141+ marked removed at runtime. The registry itself holds no sockets and starts
142+ nothing, so a unit test can build one and dispatch through
143+ ` registry.getTaskHandler(dagId, taskId) ` without any runtime involved.
132144
133- For larger projects, keep one Airflow entrypoint that imports every module that
134- registers tasks, then starts the coordinator:
145+ ` new Dag ` and ` dag.task ` take a trailing options object — ` spec ` on both, plus
146+ ` inputs ` on a task. These are not used yet; do not set them.
147+
148+ For larger projects, declare each Dag in its own module and keep one Airflow
149+ entrypoint that serves them all:
135150
136151``` ts
137- import " ./sales/tasks " ;
138- import " ./billing/tasks " ;
139- import { startCoordinator } from " @apache-airflow/ts-sdk" ;
152+ import { salesDag } from " ./sales/dag " ;
153+ import { billingDag } from " ./billing/dag " ;
154+ import { DagRegistry , serveDags } from " @apache-airflow/ts-sdk" ;
140155
141- await startCoordinator ( );
156+ await serveDags ( new DagRegistry ( salesDag , billingDag ) );
142157```
143158
159+ A bundle that collects its Dags across several modules can add them
160+ incrementally with ` registry.register(...) ` instead of passing them all to the
161+ constructor.
162+
144163Airflow launches the bundled entrypoint with ` --comm=host:port ` and
145- ` --logs=host:port ` . ` startCoordinator ()` connects to those sockets, receives
146- the task startup message, finds the registered handler for the Dag/task pair,
147- and reports the terminal task state back to Airflow.
164+ ` --logs=host:port ` . ` serveDags ()` connects to those sockets, receives the task
165+ startup message, finds the registered handler for the Dag/task pair, and
166+ reports the terminal task state back to Airflow.
148167
149168See [ ` example/ ` ] ( example/ ) for a coordinator-runtime example that packs a
150169bundle with ` airflow-ts-pack ` and uses a Python stub Dag.
0 commit comments