Python, dalle fondamenta Lezione 41 / 60

Orchestrazione: Airflow, Prefect, Dagster, il panorama del 2026

Quando cron non basta, cosa fa davvero un orchestrator, e i tre contendenti per le tue pipeline di dati.

Scrivi uno script Python che tira da un’API, trasforma con pandas, carica su Postgres. Funziona. Lo schedi con cron. Per qualche settimana va tutto bene. Poi un job fallisce alle 3 di notte e te ne accorgi martedì pomeriggio, perché cron non te lo dice. Poi un job dipende da un altro job, e cron non sa nulla di dipendenze, quindi incroci le dita sui tempi. Poi hai dieci job e non ricordi cosa gira quando. Poi qualcuno chiede “il caricamento di martedì è davvero arrivato in fondo?” e non hai niente da mostrargli.

Quello è il momento in cui ti serve un orchestrator. Questa lezione percorre il panorama del 2026, Airflow, Prefect, Dagster, la questione managed-vs-self-hosted, e termina con un semplice albero decisionale.

Cosa fa davvero un orchestrator

Cron fa una cosa: lancia un comando a un certo orario. Tutto il resto te lo costruisci tu, male. Un orchestrator fa il resto:

  • Scheduling con calendari, intervalli, espressioni cron, trigger su evento.
  • Dipendenze: “lancia B solo dopo che A è andato a buon fine”.
  • Retry: “se fallisce, riprova 3 volte con exponential backoff”.
  • Stato e storia: ogni esecuzione loggata, ogni risultato ispezionabile.
  • Osservabilità: una UI che mostra cosa è girato, cosa è fallito, quanto ci ha messo, con log su cui cliccare.
  • Alerting: dimmi su Slack quando qualcosa fallisce.
  • Backfill: “rilancia questa pipeline per ogni giorno di marzo”.
  • Resource management: pool, queue, limiti di concorrenza per task.

Puoi costruire tutto questo sopra cron e bash e una tabella di metadati Postgres. La gente lo fa, ogni anno, e ogni anno se ne pente. L’orchestrator è la cosa che esiste perché tu non debba costruire quello.

Quando ti serve uno

La soglia onesta: da qualche parte attorno a 5-10 job con dipendenze, o un singolo job abbastanza importante da dover sapere entro pochi minuti quando si rompe. Sotto a quello, cron + uno script che ti manda email in caso di fallimento basta. Sopra, l’approccio fatto in casa comincia a mordere.

Segnali che hai superato la linea:

  • Non riesci a dire a colpo d’occhio quali job sono girati oggi.
  • Stai concatenando job con && in cron e pregando sui runtime.
  • Il backfill di un range di date significa scrivere script una tantum.
  • I fallimenti vengono notati dagli umani, non dai sistemi.
  • “Questa cosa è girata?” è una domanda difficile a cui rispondere.

Se due di queste sono vere, ti serve un orchestrator.

Airflow, lo statista anziano

Airflow è uscito da Airbnb nel 2014. È il dominante orchestrator dati open-source, punto. Se entri in un team dati consolidato, le probabilità sono alte che incontrerai Airflow nella prima settimana.

Il concetto centrale è il DAG, directed acyclic graph, un file Python che dichiara task e le loro dipendenze:

from datetime import datetime, timedelta
from airflow import DAG
from airflow.operators.python import PythonOperator

def extract():
    # tira dall'API, scrivi su S3
    ...

def transform():
    # leggi S3, trasforma, riscrivi
    ...

def load():
    # leggi S3, carica su Postgres
    ...

with DAG(
    dag_id="daily_etl",
    start_date=datetime(2026, 1, 1),
    schedule="0 3 * * *",  # 3 di notte ogni giorno
    catchup=False,
    default_args={"retries": 3, "retry_delay": timedelta(minutes=5)},
) as dag:
    e = PythonOperator(task_id="extract", python_callable=extract)
    t = PythonOperator(task_id="transform", python_callable=transform)
    l = PythonOperator(task_id="load", python_callable=load)
    e >> t >> l

L’operatore >> dichiara la dipendenza: extract prima di transform prima di load. Airflow fa il parse del DAG, schedula ogni task, li lancia in ordine, ritenta sui fallimenti, e ti mostra tutto in una UI web.

Pro: ecosistema enorme. Ogni cloud provider, database, tool SaaS e message broker di cui tu abbia mai sentito parlare ha un operator o un hook Airflow. Battle-tested su scala enorme. Tanti annunci di lavoro lo cercano. L’offerta managed di Astronomer rimuove la maggior parte del dolore operativo.

Contro: install pesante. Il DB di metadati, lo scheduler, il webserver, l’executor, i worker, anche il setup minimo è fatto di diversi pezzi mobili. Il modello “il file DAG è codice Python” significa che logica di orchestrazione e logica di business tendono a impastarsi. La UI è migliorata in Airflow 2 e 3 ma sembra ancora del decennio scorso. I DAG dinamici, dove la struttura dipende da dati a runtime, sono stati retrofittati e si sente.

Usa Airflow quando: sei in un posto che già lo usa, o ti serve l’ampiezza delle integrazioni, o vuoi la storia di hiring più sicura.

Prefect, l’alternativa pythonica

Prefect è uscito nel 2018 con un pitch semplice: prendi quello che Airflow ha azzeccato (scheduling, retry, osservabilità) e riscrivilo per gente a cui Python piace davvero.

from prefect import flow, task
import httpx
import pandas as pd

@task(retries=3, retry_delay_seconds=60)
def extract(url: str) -> dict:
    return httpx.get(url).json()

@task
def transform(data: dict) -> pd.DataFrame:
    return pd.DataFrame(data["records"])

@task
def load(df: pd.DataFrame) -> None:
    df.to_sql("records", "postgresql://...", if_exists="append")

@flow(name="daily_etl")
def daily_etl(url: str):
    raw = extract(url)
    clean = transform(raw)
    load(clean)

if __name__ == "__main__":
    daily_etl.serve(name="daily", cron="0 3 * * *")

Nota la differenza. I task sono funzioni decorate. Il flow è una normale funzione Python che le chiama, e il grafo delle dipendenze è qualunque cosa le chiamate implichino. Se extract ritorna un valore che transform consuma, Prefect sa che transform dipende da extract. Niente operatori >>, niente chiamate a set_upstream. Si legge e basta.

Pro: API più pulita, i DAG dinamici sono first-class, la UI è genuinamente moderna, il loop di sviluppo locale è veloce. Prefect Cloud gestisce lo scheduler così tu fai girare solo i worker. Più facile da imparare se arrivi da zero.

Contro: ecosistema più piccolo di Airflow. Meno integrazioni preconfezionate significa più “scrivi una funzione e basta”, il che va bene, finché non volevi un operator Snowflake battle-tested. Meno comune negli annunci di lavoro, anche se quel divario si sta chiudendo.

Usa Prefect quando: parti da zero, vuoi una API più amichevole, non hai bisogno di una specifica integrazione Airflow, il tuo team valorizza la developer experience.

Dagster, il contendente data-aware

Dagster (2019+) prende un’angolazione diversa. Airflow e Prefect orchestrano task. Dagster orchestra asset, le tabelle, i file, i modelli e i report che i tuoi task producono.

from dagster import asset, Definitions
import httpx
import pandas as pd

@asset
def raw_records() -> dict:
    return httpx.get("https://api.example.com/data").json()

@asset
def clean_records(raw_records: dict) -> pd.DataFrame:
    return pd.DataFrame(raw_records["records"])

@asset
def loaded_records(clean_records: pd.DataFrame) -> None:
    clean_records.to_sql("records", "postgresql://...", if_exists="append")

defs = Definitions(assets=[raw_records, clean_records, loaded_records])

Gli argomenti delle funzioni sono le dipendenze. clean_records prende raw_records come argomento, quindi Dagster sa di dover materializzare raw_records per primo. L’unità di lavoro non è “lancia questo task”, è “assicurati che questo asset sia fresco”. Lancia un job, e Dagster capisce il set minimo di asset da ricostruire.

Questo spostamento sembra piccolo ma riformula tutto. Ottieni la lineage gratis, Dagster sa che loaded_records dipende da clean_records dipende da raw_records, e lo mostra nella UI come un grafo. Ottieni la tipizzazione, gli asset hanno tipi, e Dagster li controlla. Ottieni i partial run, “ricostruisci solo il downstream di questo singolo asset” è incorporato. Puoi esprimere le partition (un asset per giorno, per regione, per tenant) come concetto first-class invece che come hack a runtime.

Pro: modello data-native, tipi e test di livello software-engineering, lineage out of the box, si integra splendidamente con dbt e Spark, Dagster Cloud è un’offerta managed pulita.

Contro: opinionato. Il modello asset è un modo diverso di pensare, e se il tuo lavoro non ci si adatta (training ML lungo, gestori di eventi message-driven, qualunque cosa non produca davvero una “tabella”) può sembrare forzato. Community più piccola di Airflow, e meno ingegneri assumibili lo conoscono.

Usa Dagster quando: il tuo lavoro è fondamentalmente sul produrre e rinfrescare asset di dati, ti importa di lineage e tipi, il tuo team è a bordo col modello.

Self-hosted vs managed

Per tutti e tre, l’offerta managed rimuove la maggior parte del dolore operativo. In termini grossolani 2026:

  • Astronomer: Airflow managed. Il default se hai scelto Airflow e non vuoi farlo girare tu.
  • Prefect Cloud: scheduler Prefect managed. Tu fai girare i worker (spesso serverless) e Prefect fa girare il cervello.
  • Dagster Cloud: Dagster managed, con opzioni hybrid (il tuo codice, il loro control plane) e serverless.
  • Databricks Workflows / Snowflake Tasks: orchestrator incorporati dentro le piattaforme dati. Vale la pena se vivi interamente lì; limitante se non lo fai.
  • Cloud-native: AWS Step Functions, GCP Cloud Composer (che è solo Airflow managed), Azure Data Factory. Vale la pena sapere che esistono; di solito non sono la migliore developer experience Python.

Il self-hosting ti dà il controllo, costa soldi in ore di engineering, e va bene se hai un team di piattaforma. Il managed ti restituisce quelle ore al costo di qualche USD al mese. Per un team più piccolo di dieci, managed vince quasi sempre.

L’albero decisionale

Una versione corta che mi è tornata utile:

  1. Pochi job, niente dipendenze, un team amichevole che legge le email. Cron + script che mandano email sui fallimenti. Non over-ingegnerizzare.
  2. Decine di job, dipendenze vere, sei stato morso da fallimenti silenziosi. Scegli un orchestrator managed. Se hai libertà di scelta e un team piccolo: Prefect per la facilità, Dagster se il tuo lavoro è asset-shaped, Airflow se vuoi la storia di hiring più sicura.
  3. Centinaia di job, dipendenze complesse, più team, esigenze regolatorie. Self-host uno dei tre in base alle skill del team. Airflow vince sulle integrazioni e sull’hiring; Dagster vince sulla semantica dei dati; Prefect vince sulla semplicità operativa.
  4. Sei già su una piattaforma. Se i tuoi dati vivono in Databricks, usa Workflows. Se vivono in Snowflake, Tasks più dbt spesso bastano. Non aggiungere un orchestrator solo perché puoi.

Il meta-punto onesto: l’orchestrator è raramente la decisione più importante. La qualità della pipeline, idempotenza, osservabilità, testing, confini sensati tra extract / transform / load, conta molto di più del tool che la avvolge. Una pipeline pulita su Airflow batte una incasinata su Dagster, ogni volta.

Dove andiamo dopo

Nella prossima e ultima lezione di questo modulo, costruiamo una pipeline reale dall’inizio alla fine. API pubblica, trasformazione con pandas, caricamento su un database, schedulata, monitorata, idempotente. Partiremo con cron perché è la risposta giusta per la dimensione, e indicheremo dove ti laureeresti a uno degli orchestrator sopra.

Il mondo degli orchestrator è più grande di questa lezione, Airbyte, Mage, Argo Workflows, Temporal, Kestra, Windmill meritano tutti una menzione e non la ottengono. I tre che ho coperto sono il mainstream del data engineering nel 2026. Sceglietene uno, imparalo bene, e riconoscerai la forma degli altri.


Citations: Airflow docs, Prefect docs, Dagster docs. Retrieved 2026-05-01.

Cerca