DCubes
Airflow module

Lesson 3

Your first DAG

Write a two-task TaskFlow DAG, wait for the processor to parse it, unpause, and trigger a run in the UI.

beginner40 minRun on your machine

What you will be able to do

  • Write a TaskFlow DAG file in dags/ using @dag and @task
  • Unpause the DAG and trigger a run from the UI
  • Open the graph and read a task log

Why this matters for data work

A DAG file is just Python on disk. Airflow does not run it like python job.py. The DAG processor imports the file, stores the graph, and the scheduler later runs tasks. Until you have watched that loop once — file, parse, trigger, log — the UI is a mystery.

Keep schedule=None so nothing fires overnight. You will add clocks in Schedules and runs.

Concepts

TaskFlow — decorate a function with @dag and inner functions with @task. Calling those functions wires dependencies and (small) return values. Import from airflow.sdk (Airflow 3 Task SDK).

Paused at creation — our compose sets DAGS_ARE_PAUSED_AT_CREATION. New DAGs show up off. You flip the toggle, then Trigger.

Parse delay — after you save the file, wait. The DAG processor polls dags/. A syntax error means the DAG never appears; the processor log names the file.

Classic DAG() + BashOperator still exists. You will see it next lesson. First graph: two Python tasks.

Practice on your machine

Stack should already be up from Getting Started.

cd ~/dcubes/airflow-lab
cat > dags/hello_airflow.py << 'EOF'
from datetime import datetime

from airflow.sdk import dag, task


@dag(
    schedule=None,
    start_date=datetime(2024, 1, 1),
    catchup=False,
    tags=["dcubes"],
)
def hello_airflow():
    @task
    def say_hello() -> str:
        print("Hello from the DCubes Airflow lab")
        return "hello"

    @task
    def shout(word: str) -> None:
        print(word.upper())

    shout(say_hello())


hello_airflow()
EOF

Wait about 30–60 seconds, then refresh http://127.0.0.1:18080.

You should see a DAG named hello_airflow. If it is missing:

docker compose logs airflow-dag-processor --tail 50

Fix the file, save, wait again.

Run it

  1. Toggle the DAG on (unpause).
  2. Open hello_airflow.
  3. Use Trigger (sometimes labeled Trigger DAG).
  4. Open the graph. say_hello should sit upstream of shout.
  5. Click say_hello, then Logs. You want the line Hello from the DCubes Airflow lab.
  6. shout logs should include HELLO.

Both tasks success (green). That is the whole loop.

What you should see

dags/hello_airflow.py
UI: hello_airflow  (paused at first)
After trigger: say_hello  -->  shout   both success

On disk, logs/ will grow files. You do not need to read them yet; the UI is enough.

Common mistakes

  • Forgetting to call hello_airflow() at the bottom. The decorator defines the factory; the call registers the DAG.
  • schedule="@daily" on a first try. You will get confused by logical dates. Stay on None and trigger by hand.
  • Editing the file inside the container. Edit ~/dcubes/airflow-lab/dags/ on the host; the bind mount is the source of truth.
  • Import errors. from airflow.sdk import dag, task is the Airflow 3 path. Old from airflow.decorators import dag still appears in 2.x posts.

Next

Operators and dependencies