deploying-java-sdk-bundles

작성자: astronomer

컴파일된 Airflow Java SDK 번들을 빌드하고 배포하여 작업자가 실행할 수 있게 합니다. 사용자가 JVM 작업 번들을 JAR로 패키징하려 하거나, 이에 대해 질문할 때 사용하세요.

npx skills add https://github.com/astronomer/agents --skill deploying-java-sdk-bundles

Deploying Java SDK Bundles

A Java SDK deployment has one artifact: a bundle — your compiled task classes plus the SDK, packaged as a JAR (or a thin JAR alongside its dependency JARs). You build it with Gradle or Maven, then place it in a directory that the JavaCoordinator scans (jars_root) on every worker. This skill is platform-neutral; it shows the build once, then both an open-source and an Astro deployment path.

Experimental. The Java SDK is in preview. Artifact versions below are shown as ${version}; while the SDK is pre-release you may need to build the artifacts into your local Maven repository yourself (see the preview builds section).

Order of operations: build the bundle (this skill) → place it where jars_root points → configure the coordinator (configuring-airflow-language-sdks). The task code itself is authoring-java-sdk-tasks.


Build with Gradle (recommended)

Apply the SDK's Gradle plugin and declare dependencies in build.gradle:

plugins {
    id("org.apache.airflow.sdk") version "${version}"
}

repositories {
    mavenCentral()
}

dependencies {
    annotationProcessor("org.apache.airflow:airflow-sdk-processor:${version}")  // annotation API only
    implementation("org.apache.airflow:airflow-sdk:${version}")
    // Optional logging integration, e.g.:
    // implementation("org.apache.airflow:airflow-sdk-jpl:${version}")
}

airflowBundle {
    mainClass = "com.example.Main"   // your BundleBuilder entry point
    // fatJar = false                // opt out of the single-JAR build (see below)
}

Build it:

./gradlew bundle

The build/bundle/ directory then holds all required JAR(s). Notes:

  • The annotationProcessor line is needed only if you use the annotation-based API. The interface-based API doesn't need it.
  • By default the plugin produces a fat JAR (via the Shadow plugin) — one self-contained file, which avoids cross-project dependency clashes. Set fatJar = false in airflowBundle for thin JARs; you then deploy every dependency JAR too.
  • The Gradle plugin validates that mainClass exists at build time (verifyBundleMainClass).

Build with Maven

Import the BOM so artifact versions and the supervisor schema version are managed in one place:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.apache.airflow</groupId>
      <artifactId>airflow-sdk-bom</artifactId>
      <version>${version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>org.apache.airflow</groupId>
    <artifactId>airflow-sdk</artifactId>   <!-- version from the BOM -->
  </dependency>
</dependencies>

Wire the annotation processor through maven-compiler-plugin (annotation API only) so it stays off the runtime classpath. Then pick a packaging option:

  • Fat JAR (recommended): use maven-shade-plugin. In its ManifestResourceTransformer, set <mainClass> to your BundleBuilder and add the manifest entry Airflow-Supervisor-Schema-Version resolved from the BOM property ${airflow.supervisor.schema.version} (don't hard-code it). mvn package writes the JAR to target/.
  • Thin JAR: use maven-jar-plugin to set Main-Class and maven-dependency-plugin (copy-dependencies) to collect runtime JARs into target/bundle/. Here Airflow-Supervisor-Schema-Version is not needed — Airflow reads it from the airflow-sdk JAR on the classpath.

Unlike Gradle, Maven does not validate mainClass at build time; a wrong value only fails at runtime.


Logging integration

For task log records to reach Airflow's log store (and the task log view in the UI), the bundle must include exactly one SDK logging artifact per logging facade you use. Versions are managed by airflow-sdk-bom; Maven users apply the same artifact IDs.

Choosing a facade. For a greenfield project, prefer JPL (System.Logger) — it is built into the JDK, so your tasks need no extra logging API. Pick another facade only when the libraries you integrate with already log through it, so their records reach Airflow too. Preference order: JPL > SLF4J = Log4j 2 > JUL; treat JUL as legacy integration only, not a choice for new code.

FacadeArtifactSetup beyond the dependency
System.Logger (JPL)airflow-sdk-jplNone — the provider is discovered via ServiceLoader.
SLF4J 2.xairflow-sdk-slf4jNone — the binding is discovered automatically (pulls in slf4j-api for you).
Log4j 2airflow-sdk-log4j2log4j-core on the runtime classpath + AirflowAppender declared in log4j2.xml (below).
java.util.logging (JUL)airflow-sdk-julCall AirflowJulHandler.setup() in main() (below), or use a logging.properties file (see configuring-airflow-language-sdks).

Log4j 2log4j-core hosts the plugin loader that discovers the appender (log4j-api comes in transitively):

implementation("org.apache.airflow:airflow-sdk-log4j2:${version}")
runtimeOnly("org.apache.logging.log4j:log4j-core:${log4jVersion}")
<Configuration>
  <Appenders>
    <AirflowAppender name="Airflow"/>
  </Appenders>
  <Loggers>
    <Root level="info">
      <AppenderRef ref="Airflow"/>
    </Root>
  </Loggers>
</Configuration>

JUL — call AirflowJulHandler.setup() before any task runs. It clears the root logger's existing handlers (the default ConsoleHandler writes to stderr, which Airflow would otherwise capture as task.stderr at ERROR level, duplicating each record):

public static void main(String[] args) {
    AirflowJulHandler.setup();
    Server.create(args).serve(new MyBundle().build());
}

Don't double up providers. A second System.LoggerFinder implementation alongside airflow-sdk-jpl, or a second SLF4J binding (logback-classic, slf4j-simple) alongside airflow-sdk-slf4j, makes provider selection unpredictable.


Preview builds (before a stable release)

Skip this section if you depend on a stable release. Once you pin a released version (e.g. 1.0.0) published to Maven Central, the mavenCentral() repository in the build snippets above is enough.

While the SDK is pre-release, the documented path is to build the artifacts and the Gradle plugin from the Airflow repo into your local Maven repository:

# in apache/airflow's java-sdk/ directory
./gradlew publishToMavenLocal -PskipSigning=true

Then add mavenLocal() in your project, in both pluginManagement (in settings.gradle) and project repositories (in build.gradle) — this is how the SDK's own example project resolves it.

Once -SNAPSHOT artifacts are published to Apache's snapshot Nexus, that repository can stand in for the local build (same two places):

maven {
    name = "apacheSnapshots"
    url = "https://repository.apache.org/content/repositories/snapshots/"
    mavenContent { snapshotsOnly() }
}

Snapshots move; force a refresh with ./gradlew bundle --refresh-dependencies. (For Maven, add the same repository to <repositories> and <pluginRepositories>.)


Place the bundle where the coordinator scans

The coordinator scans jars_root recursively and builds the classpath automatically, so you copy the whole output directory:

cp build/bundle/* /opt/airflow/jars/    # /opt/airflow/jars == jars_root

The worker also needs a JRE 17+. Wiring the coordinator to this directory is covered in configuring-airflow-language-sdks.


Deployment paths

Astronomer tooling is not required — the SDK runs on any Airflow with the Task SDK. Choose the path that matches the user's setup.

Open-source (Docker / Kubernetes)

Bake the JRE and the bundle into your Airflow image, or mount them:

FROM apache/airflow:3          # pin a specific 3.x in production
USER root
RUN apt-get update \
    && apt-get install -y --no-install-recommends default-jre-headless \
    && apt-get clean && rm -rf /var/lib/apt/lists/*
RUN mkdir -p /opt/airflow/jars
COPY build/bundle/ /opt/airflow/jars/
USER airflow

On Kubernetes (Helm chart), bake the JAR into a custom image as above, or mount it via a shared volume; set the [sdk] config through environment variables on the worker/scheduler. See deploying-airflow for the broader Docker Compose and Helm workflow.

Astro (one option, not required)

If the user is on Astronomer's Astro CLI, the same idea maps onto an Astro project:

  1. Build the bundle, then stage it in the project: mkdir -p include/jars && cp ../java-bundle/build/bundle/*.jar include/jars/.

  2. Edit the project Dockerfile to install a JRE and copy the JARs to the coordinator's directory:

    FROM quay.io/astronomer/astro-runtime:<version>
    USER root
    RUN apt-get update \
        && apt-get install -y --no-install-recommends default-jre-headless \
        && apt-get clean && rm -rf /var/lib/apt/lists/*
    RUN mkdir -p /opt/airflow/jars
    COPY include/jars/ /opt/airflow/jars/
    USER airflow
    
  3. Put the coordinator config in the project's .env (loaded automatically) — see configuring-airflow-language-sdks for the AIRFLOW__SDK__* values.

  4. astro dev start (or astro dev restart after changes) builds the image and starts Airflow locally; deploy with astro deploy as usual.

Don't pin Astro Runtime / Airflow versions from memory — read the generated Dockerfile or check current docs. While the SDK and Airflow 3.3 are in preview, a beta/dev Astro Runtime image may be required.


Deploy checklist

  • Bundle built (./gradlew bundle or mvn package) and mainClass points at your BundleBuilder.
  • annotationProcessor present iff you use the annotation API.
  • JAR(s) copied into the worker's jars_root directory; with thin JARs, dependency JARs too.
  • JRE 17+ available on the worker.
  • Coordinator + queue_to_coordinator configured (configuring-airflow-language-sdks).
  • If multiple executable JARs exist under jars_root, set main_class explicitly.

Related Skills

  • authoring-java-sdk-tasks: Write the Java task code and the matching Python stubs.
  • configuring-airflow-language-sdks: Register the coordinator and route the queue.
  • deploying-airflow: General Airflow deployment (Astro, Docker Compose, Kubernetes).
  • setting-up-astro-project: Initialize and configure an Astro project.

astronomer의 다른 스킬

airflow
astronomer
Apache Airflow DAG, 실행, 작업 및 시스템 구성을 쿼리, 관리 및 문제 해결합니다. DAG 검사, 실행 관리, 작업 로깅, 구성 쿼리 및 직접 REST API 액세스에 걸쳐 30개 이상의 명령을 지원합니다. 지속적인 구성으로 여러 Airflow 인스턴스를 관리하고 로컬 및 Astro 배포를 자동으로 검색합니다. DAG 실행을 동기식(완료 대기) 또는 비동기식으로 트리거하고, 실패를 진단하고, 재시도를 위해 실행을 지우고, 재시도/맵 인덱스 필터링을 통해 작업 로그에 액세스합니다. 출력...
official
airflow-hitl
astronomer
인간 승인 게이트, 폼 입력, 그리고 지연 가능 연산자를 사용한 Airflow DAG 내 분기 처리. 네 가지 연산자 유형: 승인/거부 결정을 위한 ApprovalOperator, 폼을 통한 다중 옵션 선택을 위한 HITLOperator, 인간 주도 작업 라우팅을 위한 HITLBranchOperator, 폼 데이터 수집을 위한 HITLEntryOperator. 모든 연산자는 지연 가능하며, Airflow UI의 Required Actions 탭 또는 REST API를 통해 인간 응답을 기다리는 동안 작업자 슬롯을 해제합니다. 선택적 기능 지원 포함: 사용자 정의...
official
airflow-state-store
astronomer
Persists task and asset state across retries and DAG runs using Airflow 3.3's AIP-103 key/value stores (`task_state_store`, `asset_state_store`) and the…
official
analyzing-data
astronomer
데이터 웨어하우스에 질의하여 캐시된 패턴과 개념 매핑을 통해 비즈니스 질문에 답변합니다. 반복되는 질문 유형에 대한 패턴 조회 및 캐싱을 지원하며, 결과 기록을 통해 향후 질의를 개선합니다. 개념-테이블 매핑 캐시와 INFORMATION_SCHEMA 또는 코드베이스 grep을 통한 테이블 스키마 탐색을 포함합니다. 분석을 위해 Polars 또는 Pandas DataFrame을 반환하는 run_sql() 및 run_sql_pandas() 커널 함수를 제공합니다. 개념, 패턴 및 테이블 캐시를 관리하기 위한 CLI 명령어와 추가 기능을 포함합니다.
official
annotating-task-lineage
astronomer
Airflow 태스크에 인렛과 아웃렛을 사용하여 데이터 계보를 주석 처리합니다. 입력 및 출력을 데이터베이스, 데이터 웨어하우스, 클라우드 스토리지 전반에 걸쳐 정의하기 위해 OpenLineage Dataset 객체, Airflow Assets 및 Airflow Datasets를 지원합니다. 운영자에 내장된 OpenLineage 추출기가 없는 경우 대체 수단으로 사용되며, 사용자 정의 추출기와 OpenLineage 메서드가 우선 적용되는 4단계 우선순위 시스템을 따릅니다. Snowflake, BigQuery, S3 및 PostgreSQL에 대한 일관된 명명을 보장하는 데이터셋 명명 헬퍼를 포함합니다.
official
authoring-dags
astronomer
Apache Airflow DAG 생성을 위한 안내 워크플로우로, 검증 및 테스트 통합을 포함합니다. 구조화된 6단계 접근 방식: 환경 및 기존 패턴 발견, DAG 구조 계획, 모범 사례에 따른 구현, af CLI 명령어로 검증, 사용자 동의 하에 테스트, 수정 반복. 발견을 위한 CLI 명령어(af config connections, af config providers, af dags list)와 검증을 위한 명령어(af dags errors, af dags get, af dags explore)는 DAG에 대한 즉각적인 피드백을 제공합니다...
official
authoring-go-sdk-tasks
astronomer
Writes Airflow task logic in Go using the Airflow Go SDK. Use when the user wants to implement Airflow tasks in Go, asks about `BundleProvider`/`RegisterDags`,…
official
authoring-java-sdk-tasks
astronomer
Airflow 작업 로직을 Java, Kotlin 또는 Airflow Java SDK를 사용하는 모든 JVM 언어로 작성합니다. 사용자가 Java/JVM에서 Airflow 작업을 구현하려 하거나, 요청할 때 사용합니다…
official