Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
dfa07b0
Add Task Coordinators and Dag File Processor
jason810496 Apr 8, 2026
dd2e24d
Add initial Java provider for Apache Airflow
jason810496 Apr 8, 2026
9a771f5
Add common selector loop utilities for socket I/O handling for subpro…
jason810496 Apr 10, 2026
a8386fc
Implement Java DAG file processor with TCP communication bridge
jason810496 Apr 9, 2026
4c2ee0e
Make JavaDagFileProcessor.can_handle aware of jar file content
jason810496 Apr 9, 2026
933171c
Fix java process startup issue
jason810496 Apr 9, 2026
5c51d0d
Fix sockets bidning
jason810496 Apr 9, 2026
18a70d7
Refactor Java DAG file processor to use selector-based I/O multiplexi…
jason810496 Apr 10, 2026
78eb3ec
Add BaseLocaleCoordinator for non-Python DAG file processing and task…
jason810496 Apr 10, 2026
2895195
Implement JavaLocaleCoordinator
jason810496 Apr 10, 2026
d4f5ce3
Add Java task coordinator and entrypoint for locale-specific execution
jason810496 Apr 13, 2026
e31ec60
Refactor Java provider to with generic process coordinators and updat…
jason810496 Apr 13, 2026
7c8f352
Fix Coordinator by getting the correct dag bundle and dag path
jason810496 Apr 14, 2026
5df4fe0
Make @task.stub(language=java) works
jason810496 Apr 15, 2026
340ef89
Make coordinator respect Jar bundle based on TI workload type
jason810496 Apr 16, 2026
e59df36
Add java_sdk_setup script for Breeze
jason810496 Apr 16, 2026
03631ed
Add get_code_from_file interface for BaseLocaleCoordinator
jason810496 Apr 16, 2026
fc17fae
Fix the 'Pure Java Dag' disappear in metadata DB issue
jason810496 Apr 17, 2026
1978b92
Refactor process coordinators to runtime coordinators
jason810496 Apr 17, 2026
ba4ba6c
Rename stub operator language field as sdk
jason810496 Apr 23, 2026
6eb4784
Rename languages.java provider to sdk.java
jason810496 Apr 23, 2026
c898258
Add unit tests for socket handling and selector loop functionality
jason810496 Apr 23, 2026
59496a3
Move TaskInstanceDTO to share to make task_runner retrieve TI.queue
jason810496 Apr 21, 2026
fc642fb
Add [workers/queue_to_runtime_mapping]
jason810496 Apr 22, 2026
26764dd
Remove the sdk field from stub operator and respect [workers/queue_to…
jason810496 Apr 23, 2026
7625345
Rename `[workers] queue_to_runtime_mapping` to `[sdk] queue_to_sdk`
jason810496 Apr 23, 2026
5ba3967
Simplify coordinator-related names (#1569)
uranusjr Apr 24, 2026
ea4eef9
CI: Add mypy and unit tests for shared/workloads
jason810496 Apr 28, 2026
5c803dd
CI: Fix DB migration and breeze images
jason810496 Apr 28, 2026
1c97cf3
CI: Fix failing items
jason810496 Apr 28, 2026
9c7b41c
CI: Fix failing items
jason810496 Apr 28, 2026
81d720b
CI: Add compat for create_runtime_ti pytest fixture
jason810496 Apr 28, 2026
f8388c9
CI: Fix Java provider test to include configuration options
jason810496 Apr 28, 2026
6467fb1
CI: Fix self-review nits
jason810496 Apr 28, 2026
375eaa9
Revert MappedOperator change
jason810496 Apr 28, 2026
e615c97
CI: Fix failing items
jason810496 Apr 28, 2026
36d0bdf
CI: Fix Task SDK test_task_runner failures using TaskInstanceDTO
jason810496 Apr 28, 2026
4c58701
CI: Skip non-JAR paths in JavaCoordinator.can_handle_dag_file
jason810496 Apr 28, 2026
c938a38
CI: Drop literal Example: line from queue_to_sdk config description
jason810496 Apr 28, 2026
abfade1
CI: Skip sdk-java provider in compat tests for older Airflow
jason810496 Apr 28, 2026
52ce0ff
CI: Fix MyPy Liskov violation in JavaCoordinator.task_execution_cmd
jason810496 Apr 28, 2026
e915473
CI: Fix sdk-java docs build warnings
jason810496 Apr 28, 2026
316c29a
CI: Update SDK Java configuration and documentation references
jason810496 Apr 29, 2026
8281739
CI: Update map_index handling and add fixture to restore process cont…
jason810496 Apr 29, 2026
58a6001
CI: Refactor map_index handling and update time travel decorators for…
jason810496 Apr 30, 2026
d9c2b4a
CI: Replace TaskInstance with TaskInstanceDTO and add additional para…
jason810496 Apr 30, 2026
66eece7
CI: Update test cases to use -1 for map_index and add additional para…
jason810496 Apr 30, 2026
837d964
Remove shared workloads dependency and refactor TaskInstanceDTO usage
jason810496 Apr 30, 2026
b1125a1
Move sdk.java out of provider as apache-airflow-coordinators-java dis…
jason810496 May 6, 2026
044f3ee
Add Task Coordinators and Dag File Processor
jason810496 Apr 8, 2026
0c6e0ba
Add initial Java provider for Apache Airflow
jason810496 Apr 8, 2026
4b45c31
Implement Java DAG file processor with TCP communication bridge
jason810496 Apr 9, 2026
9b876b2
Make JavaDagFileProcessor.can_handle aware of jar file content
jason810496 Apr 9, 2026
ac239b1
Fix java process startup issue
jason810496 Apr 9, 2026
585e336
Fix sockets bidning
jason810496 Apr 9, 2026
d0cd683
Refactor Java DAG file processor to use selector-based I/O multiplexi…
jason810496 Apr 10, 2026
5645afc
Implement JavaLocaleCoordinator
jason810496 Apr 10, 2026
5dc37ef
Add Java task coordinator and entrypoint for locale-specific execution
jason810496 Apr 13, 2026
64416c4
Refactor Java provider to with generic process coordinators and updat…
jason810496 Apr 13, 2026
c2c8fd9
Fix Coordinator by getting the correct dag bundle and dag path
jason810496 Apr 14, 2026
2cf2b85
Make @task.stub(language=java) works
jason810496 Apr 15, 2026
bc30f01
Make coordinator respect Jar bundle based on TI workload type
jason810496 Apr 16, 2026
d542bca
Add get_code_from_file interface for BaseLocaleCoordinator
jason810496 Apr 16, 2026
ac21b39
Fix the 'Pure Java Dag' disappear in metadata DB issue
jason810496 Apr 17, 2026
0891041
Refactor process coordinators to runtime coordinators
jason810496 Apr 17, 2026
8462e1c
Initial Java-SDK
jason810496 Apr 17, 2026
30aae4d
Add Java SDK e2e tests
jason810496 Apr 20, 2026
07d1e50
Add check-java-serialization-compatibility prek hook
jason810496 Apr 20, 2026
32b135b
Breeze start-airflow setup with Java SDK
jason810496 Apr 22, 2026
e01698c
Rename stub operator language field as sdk
jason810496 Apr 23, 2026
fb815c3
Cache gradle deps for breeze start-airflow
jason810496 Apr 23, 2026
4688d77
Rename languages.java provider to sdk.java
jason810496 Apr 23, 2026
19348e3
Move TaskInstanceDTO to share to make task_runner retrieve TI.queue
jason810496 Apr 21, 2026
04fa3cf
Add [workers/queue_to_runtime_mapping]
jason810496 Apr 22, 2026
bc6eb17
Remove the sdk field from stub operator and respect [workers/queue_to…
jason810496 Apr 23, 2026
dbfa343
Rename `[workers] queue_to_runtime_mapping` to `[sdk] queue_to_sdk`
jason810496 Apr 23, 2026
1f6644f
Simplify coordinator-related names (#1569)
uranusjr Apr 24, 2026
21dbbda
Add ADRs for JavaSDK and Coordinator
jason810496 Apr 28, 2026
4d4bb81
Update new coordinator config setup in java_sdk_build.sh
jason810496 May 7, 2026
0225b6f
Update JavaSDK e2e setup with the latest coordinator config
jason810496 May 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
!task-sdk/
!airflow-ctl/
!go-sdk/
!sdk/

# Add all "test" distributions
!tests
Expand Down
3 changes: 3 additions & 0 deletions .github/boring-cyborg.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ labelPRBasedOnFilePath:
provider:keycloak:
- providers/keycloak/**

provider:sdk-java:
- providers/sdk/java/**

provider:microsoft-azure:
- providers/microsoft/azure/**

Expand Down
22 changes: 22 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,12 @@ repos:
language: python
pass_filenames: false
files: ^dev/registry/registry_tools/types\.py$|^registry/src/_data/types\.json$
- id: check-task-instance-dto-sync
name: Check BaseTaskInstanceDTO duplicate is in sync between core and task-sdk
entry: ./scripts/ci/prek/check_task_instance_dto_sync.py
language: python
pass_filenames: false
files: ^airflow-core/src/airflow/executors/workloads/task\.py$|^task-sdk/src/airflow/sdk/execution_time/workloads/task\.py$
- id: ruff
name: Run 'ruff' for extremely fast Python linting
description: "Run 'ruff' for extremely fast Python linting"
Expand Down Expand Up @@ -1111,6 +1117,22 @@ repos:
files: ^airflow-core/src/airflow/migrations/versions/.*\.py$
additional_dependencies: [rich>=13.6.0]
require_serial: true
- id: check-java-serialization-compatibility
name: Check Java SDK serialization compatibility
description: >-
Verify that the Java and Python SDKs produce identical DAG serialization
for all test cases defined in java-sdk/validation/serialization/test_dags.yaml
entry: ./scripts/ci/prek/check_java_serialization_compatibility.py
language: python
stages: ['manual']
pass_filenames: false
require_serial: true
files: >
(?x)
^java-sdk/sdk/src/.*\.(kt|java)$|
^java-sdk/validation/serialization/.*$|
^airflow-core/src/airflow/serialization/.*\.py$|
^task-sdk/src/airflow/sdk/definitions/.*\.py$
## ADD MOST PREK HOOK ABOVE THAT LINE
# The below prek hooks are those requiring CI image to be built
## ONLY ADD PREK HOOKS HERE THAT REQUIRE CI IMAGE
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -1048,8 +1048,8 @@ function install_airflow_and_providers_from_docker_context_files(){
install_airflow_core_distribution=("apache-airflow-core==${AIRFLOW_VERSION}")
fi

# Find Provider/TaskSDK/CTL distributions in docker-context files
readarray -t airflow_distributions< <(python /scripts/docker/get_distribution_specs.py /docker-context-files/apache?airflow?{providers,task?sdk,airflowctl}*.{whl,tar.gz} 2>/dev/null || true)
# Find Provider/TaskSDK/CTL/Coordinator distributions in docker-context files
readarray -t airflow_distributions< <(python /scripts/docker/get_distribution_specs.py /docker-context-files/apache?airflow?{providers,task?sdk,airflowctl,coordinators?java}*.{whl,tar.gz} 2>/dev/null || true)
echo
echo "${COLOR_BLUE}Found provider distributions in docker-context-files folder: ${airflow_distributions[*]}${COLOR_RESET}"
echo
Expand Down
24 changes: 24 additions & 0 deletions Dockerfile.ci
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,30 @@ function environment_initialization() {
export AIRFLOW__SCHEDULER__GO_WORKER=True
fi

if [[ ${JAVA_SDK=} == "true" ]]; then
echo
echo "${COLOR_BLUE}Setting up Java SDK${COLOR_RESET}"
echo

# Install Java and the Java SDK provider
bash /opt/airflow/scripts/in_container/java_sdk_setup.sh

# Set JAVA_HOME and PATH before Gradle build so gradlew can find java
export JAVA_HOME=/files/openjdk
export PATH=/files/openjdk/bin:${PATH}

# Build both Java SDK bundles (stub + pure Java)
export JAVA_SDK_SRC_DIR=/opt/airflow/java-sdk
export BUNDLES_OUTPUT_DIR=/files/java-sdk-bundles
bash /opt/airflow/scripts/in_container/java_sdk_build.sh

# Source the generated environment configuration
# shellcheck disable=SC1091
source /files/java-sdk-bundles/java_sdk_env.sh

echo "${COLOR_BLUE}Java SDK setup complete.${COLOR_RESET}"
fi

RUN_TESTS=${RUN_TESTS:="false"}
CI=${CI:="false"}

Expand Down
11 changes: 11 additions & 0 deletions airflow-core/docs/extra-packages-ref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,17 @@ all the ``airflow`` packages together - similarly to what happened in Airflow 2.
``airflow-task-sdk`` separately, if you want to install providers, you need to install them separately as
``apache-airflow-providers-*`` distribution packages.

Multi-Language extras
=====================

These are extras that add dependencies needed for integration with other languages runtimes. Currently we have only Java SDK related extra, but in the future we might add more extras related to other languages runtimes.

+----------+------------------------------------------+------------------------------------------------------------------+
| extra | install command | enables |
+==========+==========================================+==================================================================+
| sdk.java | ``pip install apache-airflow[sdk.java]`` | JavaCoordinator for both dag processing and workload execution. |
+----------+------------------------------------------+------------------------------------------------------------------+

Apache Software extras
======================

Expand Down
2 changes: 2 additions & 0 deletions airflow-core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ exclude = [
"../shared/serialization/src/airflow_shared/serialization" = "src/airflow/_shared/serialization"
"../shared/state/src/airflow_shared/state" = "src/airflow/_shared/state"
"../shared/timezones/src/airflow_shared/timezones" = "src/airflow/_shared/timezones"
"../shared/workloads/src/airflow_shared/workloads" = "src/airflow/_shared/workloads"
"../shared/listeners/src/airflow_shared/listeners" = "src/airflow/_shared/listeners"
"../shared/plugins_manager/src/airflow_shared/plugins_manager" = "src/airflow/_shared/plugins_manager"
"../shared/providers_discovery/src/airflow_shared/providers_discovery" = "src/airflow/_shared/providers_discovery"
Expand Down Expand Up @@ -337,6 +338,7 @@ shared_distributions = [
"apache-airflow-shared-serialization",
"apache-airflow-shared-state",
"apache-airflow-shared-timezones",
"apache-airflow-shared-workloads",
"apache-airflow-shared-plugins-manager",
"apache-airflow-shared-providers-discovery",
]
1 change: 1 addition & 0 deletions airflow-core/src/airflow/_shared/workloads
37 changes: 37 additions & 0 deletions airflow-core/src/airflow/config_templates/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1967,6 +1967,43 @@ workers:
type: integer
example: ~
default: "60"
sdk:
description: Settings for non-Python SDK runtime coordination
options:
coordinators:
description: |
JSON list of runtime coordinator entries.

Each entry is an object with ``name``, ``classpath`` and optional
``kwargs``. ``classpath`` is resolved via ``import_string`` and
constructed with ``kwargs`` once per process. Entries are
independent instances, so the same ``classpath`` can be configured
multiple times with different ``kwargs`` (for example, two
``JavaCoordinator`` instances pinned to different JDK versions).
version_added: 3.1.7
type: string
example: |
[
{
"name": "jdk-17",
"classpath": "airflow.sdk.coordinators.java.JavaCoordinator",
"kwargs": {"java_executable": "/usr/lib/jvm/java-17-openjdk/bin/java", "jvm_args": ["-Xmx1024m"]}
}
]
default: ~
queue_to_coordinator:
description: |
JSON mapping of queue names to coordinator ``name`` from
``[sdk] coordinators``.

When a task's ``language`` field is not set, this mapping is checked
to route the task to a configured coordinator instance based on its
queue. This is useful when queues are used as environment or
isolation identifiers (e.g. ``legacy-java``, ``modern-java``).
version_added: 3.1.7
type: string
example: '{"legacy-java": "jdk-11", "modern-java": "jdk-17"}'
default: ~
api_auth:
description: Settings relating to authentication on the Airflow APIs
options:
Expand Down
19 changes: 18 additions & 1 deletion airflow-core/src/airflow/dag_processing/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ class DagFileProcessorManager(LoggingMixin):
factory=_config_get_factory("dag_processor", "file_parsing_sort_mode")
)

_runtime_file_extensions: tuple[str, ...] | None = attrs.field(default=None, init=False)
"""File extensions registered by runtime coordinators (e.g. ".jar"). Lazily populated."""

_api_server: InProcessExecutionAPI = attrs.field(init=False, factory=InProcessExecutionAPI)
"""API server to interact with Metadata DB"""

Expand Down Expand Up @@ -815,14 +818,28 @@ def _find_files_in_bundle(self, bundle: BaseDagBundle) -> list[Path]:

return rel_paths

def _get_runtime_file_extensions(self) -> tuple[str, ...]:
"""Collect file extensions from configured runtime coordinators (cached after first call)."""
if self._runtime_file_extensions is not None:
return self._runtime_file_extensions

from airflow.sdk.execution_time.coordinator import get_coordinator_manager

self._runtime_file_extensions = get_coordinator_manager().file_extensions()
return self._runtime_file_extensions

def _get_observed_filelocs(self, present: set[DagFileInfo]) -> set[str]:
"""
Return observed DAG source paths for bundle entries.

For regular files this includes the relative file path.
For ZIP archives this includes DAG-like inner paths such as
``archive.zip/dag.py``.

Runtime coordinator file extensions (e.g. ``.jar``) are treated as
opaque files rather than ZIP archives.
"""
runtime_extensions = self._get_runtime_file_extensions()

def find_zipped_dags(abs_path: os.PathLike) -> Iterator[str]:
"""Yield absolute paths for DAG-like files inside a ZIP archive."""
Expand All @@ -837,7 +854,7 @@ def find_zipped_dags(abs_path: os.PathLike) -> Iterator[str]:
observed_filelocs: set[str] = set()
for info in present:
abs_path = str(info.absolute_path)
if abs_path.endswith(".py") or not zipfile.is_zipfile(abs_path):
if abs_path.endswith((".py", *runtime_extensions)) or not zipfile.is_zipfile(abs_path):
observed_filelocs.add(str(info.rel_path))
else:
if TYPE_CHECKING:
Expand Down
44 changes: 40 additions & 4 deletions airflow-core/src/airflow/dag_processing/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from __future__ import annotations

import contextlib
import functools
import importlib
import logging
import os
Expand Down Expand Up @@ -76,8 +77,6 @@
from airflow.utils.state import TaskInstanceState

if TYPE_CHECKING:
from socket import socket

from structlog.typing import FilteringBoundLogger

from airflow.api_fastapi.execution_api.app import InProcessExecutionAPI
Expand All @@ -86,6 +85,7 @@
from airflow.sdk.definitions.context import Context
from airflow.sdk.definitions.dag import DAG
from airflow.sdk.definitions.mappedoperator import MappedOperator
from airflow.sdk.execution_time.supervisor import SelectorCallback
from airflow.typing_compat import Self


Expand Down Expand Up @@ -553,7 +553,14 @@ def start( # type: ignore[override]
) -> Self:
logger = kwargs["logger"]

_pre_import_airflow_modules(os.fspath(path), logger)
# Check if a configured runtime coordinator should handle this file
logger.debug("Checking for runtime coordinator entrypoint for file", path=path)
resolved_target = cls._resolve_processor_target(path, bundle_name, bundle_path, logger)
if resolved_target is not None:
target = resolved_target
logger.debug("Resolved runtime coordinator entrypoint for file", path=path)
else:
_pre_import_airflow_modules(os.fspath(path), logger)

proc: Self = super().start(
target=target,
Expand All @@ -566,6 +573,35 @@ def start( # type: ignore[override]
proc._on_child_started(callbacks, path, bundle_path, bundle_name)
return proc

@staticmethod
def _resolve_processor_target(
path: str | os.PathLike[str],
bundle_name: str,
bundle_path: Path,
log: FilteringBoundLogger,
) -> Callable[[], None] | None:
"""
Return the entrypoint of the first runtime coordinator that can handle *path*.

The returned callable is a ``functools.partial`` that binds *path*, *bundle_name*
and *bundle_path* so the supervisor can pass it as a no-arg ``target`` to
``WatchedSubprocess.start``.
"""
from airflow.sdk.execution_time.coordinator import get_coordinator_manager

coordinator = get_coordinator_manager().for_dag_file(bundle_name, path)
if coordinator is None:
log.debug("No runtime coordinator found for file %s, using default processor", path)
return None

log.debug("Using runtime coordinator %s for file %s", type(coordinator).__qualname__, path)
return functools.partial(
coordinator.run_dag_parsing,
path=os.fspath(path),
bundle_name=bundle_name,
bundle_path=os.fspath(bundle_path),
)

def _on_child_started(
self,
callbacks: list[CallbackRequest],
Expand All @@ -591,7 +627,7 @@ def _get_target_loggers(self) -> tuple[FilteringBoundLogger, ...]:

def _create_log_forwarder(
self, loggers: tuple[FilteringBoundLogger, ...], name: str, log_level: int = logging.INFO
) -> Callable[[socket], bool]:
) -> SelectorCallback:
return super()._create_log_forwarder(loggers, name.replace("task.", "dag_processor.", 1), log_level)

def _handle_request(self, msg: ToManager, log: FilteringBoundLogger, req_id: int) -> None:
Expand Down
5 changes: 2 additions & 3 deletions airflow-core/src/airflow/executors/base_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -650,11 +650,10 @@ def run_workload(

if isinstance(workload, ExecuteTask):
from airflow.sdk.execution_time.supervisor import supervise_task
from airflow.sdk.execution_time.workloads.task import TaskInstanceDTO as SDKTaskInstanceDTO

# workload.ti is a TaskInstanceDTO which duck-types as TaskInstance.
# TODO: Create a protocol for this.
return supervise_task(
ti=workload.ti, # type: ignore[arg-type]
ti=SDKTaskInstanceDTO.model_validate(workload.ti, from_attributes=True),
bundle_info=workload.bundle_info,
dag_rel_path=workload.dag_rel_path,
token=workload.token,
Expand Down
17 changes: 14 additions & 3 deletions airflow-core/src/airflow/executors/workloads/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,14 @@
from airflow.models.taskinstancekey import TaskInstanceKey


class TaskInstanceDTO(BaseModel):
"""Schema for TaskInstance with minimal required fields needed for Executors and Task SDK."""
class BaseTaskInstanceDTO(BaseModel):
"""
Base schema for TaskInstance with the minimal fields shared by Executors and the Task SDK.

This definition is duplicated in :mod:`airflow.sdk.execution_time.workloads.task`
and the two are kept in sync by the ``check-task-instance-dto-sync`` prek
hook. Update both files together.
"""

id: uuid.UUID
dag_version_id: uuid.UUID
Expand All @@ -48,11 +54,16 @@ class TaskInstanceDTO(BaseModel):
queue: str
priority_weight: int
executor_config: dict | None = Field(default=None, exclude=True)
external_executor_id: str | None = Field(default=None, exclude=True)

parent_context_carrier: dict | None = None
context_carrier: dict | None = None


class TaskInstanceDTO(BaseTaskInstanceDTO):
"""TaskInstanceDTO with executor-specific ``external_executor_id`` field and ``key`` property."""

external_executor_id: str | None = Field(default=None, exclude=True)

# TODO: Task-SDK: Can we replace TaskInstanceKey with just the uuid across the codebase?
@property
def key(self) -> TaskInstanceKey:
Expand Down
8 changes: 8 additions & 0 deletions airflow-core/src/airflow/models/dagcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ def code(cls, dag_id, session: Session = NEW_SESSION) -> str:

@staticmethod
def get_code_from_file(fileloc):
# Try from runtime coordinator first.
from airflow.sdk.execution_time.coordinator import get_coordinator_manager

coordinator = get_coordinator_manager().for_dag_file("", fileloc)
if coordinator is not None:
return coordinator.get_code_from_file(fileloc)

# Then fallback to python native
try:
with open_maybe_zipped(fileloc, "r") as f:
code = f.read()
Expand Down
7 changes: 7 additions & 0 deletions airflow-core/src/airflow/provider.yaml.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,13 @@
}
}
},
"coordinators": {
"type": "array",
"description": "Runtime Coordinator class names (BaseCoordinator subclasses)",
"items": {
"type": "string"
}
},
"source-date-epoch": {
"type": "integer",
"description": "Source date epoch - seconds since epoch (gmtime) when the release documentation was prepared. Used to generate reproducible package builds with flint.",
Expand Down
Loading
Loading