Architettura di dati e sistemi, dalle fondamenta Lezione 57 / 80

Orchestration in profondità: Airflow, Prefect, Dagster, Argo Workflows

I quattro contendenti, quando ciascuno vince, framing asset-oriented contro task-oriented, e la decisione managed contro self-hosted.

Il Modulo 7 si è chiuso con il substrato di runtime: Kubernetes per la maggior parte dei team dati nel 2026, con il pattern degli operator a fare il lavoro pesante per Spark, Flink e il resto. Il Modulo 8 parte un livello più in alto. Ora che i workload hanno un posto in cui girare, cosa li fa partire, in che ordine, con quali dipendenze, e chi li tiene d’occhio quando falliscono? Questo è il lavoro dell’orchestrator, e la scelta dell’orchestrator è una delle decisioni più gravide di conseguenze che una piattaforma dati prenda.

La scelta si è arricchita negli ultimi anni. Per gran parte degli anni 2010 “orchestrator” voleva dire di fatto Airflow, con cron e script fatti in casa come alternativa per la piccola scala. Nel 2026 ci sono quattro contendenti seri, ciascuno con una nicchia difendibile: Airflow, Prefect, Dagster e Argo Workflows. Non sono intercambiabili. Fanno assunzioni diverse su cosa sia una pipeline, quale stato l’orchestrator possieda, e che forma debba avere il modello mentale dell’utente. Sceglierne uno è una vera decisione architetturale, non una questione di gusto.

Questa lezione passa in rassegna cosa fa un orchestrator, poi ciascuno dei quattro, poi il framing che aiuta un team a scegliere: task-oriented contro asset-oriented (che la lezione 58 espande), e managed contro self-hosted (che di solito in pratica è la prima decisione che si prende).

Cosa fa davvero un orchestrator

Tolto il marketing, un orchestrator è responsabile di una lista piccola e stabile di compiti.

Schedulare i job. Esegui questa pipeline alle 02:00 ogni giorno. Esegui quell’altra quando un nuovo file atterra in S3. Esegui questa terza quando una pipeline upstream si completa con successo.

Tracciare lo stato. Questo task è in coda. Quello sta girando. L’altro è finito alle 02:14 con exit code 0. Una storia di quali task sono girati, quando, e come sono finiti è il log persistente dell’orchestrator di cosa ha fatto il tuo sistema dati.

Gestire le dipendenze. Il task B dipende dal task A. Non far partire B finché A non ha successo. Se A fallisce, non far partire B. Se A è in ritardo, B aspetta.

Fare retry sui fallimenti. I fallimenti transienti (un singhiozzo di rete, una API instabile) dovrebbero fare retry automaticamente, con backoff, fino a un limite configurato. I fallimenti veri devono affiorare a una persona.

Avvisare sui problemi. Un task fallito, un task che è girato troppo a lungo, una SLA mancata: l’orchestrator emette un segnale che una persona raccoglie. Slack, PagerDuty, email, qualunque cosa il team usi.

Darti una UI. Quando qualcosa va storto alle 03:00 ti serve uno schermo che mostri le ultime ventiquattr’ore di run, i task falliti, i log e il grafo delle dipendenze, idealmente senza dover leggere il codice sorgente.

Tutti gli orchestrator fanno queste cose. Le differenze stanno in come le espongono, quali altre cose si portano dietro, e quali assunzioni cuociono dentro al modello.

Airflow: l’originale

Airflow è uscito da Airbnb nel 2014, è entrato nell’incubator Apache nel 2016, ed è arrivato allo status di top-level project nel 2019. Maxime Beauchemin, l’autore originale, lo ha scritto in risposta all’esperienza dolorosa di gestire pipeline batch via cron e script artigianali in un’azienda che stava scalando in fretta. La scelta di design che ha definito Airflow erano i DAG Python-first: le pipeline sono file Python che importano operator e li cablano insieme, e lo scheduler legge questi file per capire cosa eseguire.

Quella scelta taglia in entrambi i versi.

Il lato buono: un ecosistema enorme di operator viene rilasciato con Airflow o come pacchetti della community. BigQuery, Snowflake, Redshift, S3, GCS, Spark, dbt, Slack, i servizi di compute e storage di ogni grande cloud, ogni grande tool dei dati. Se vuoi orchestrare qualcosa, l’operator probabilmente esiste. Gli anni 2020 hanno anche portato il deployment Kubernetes-native via Helm chart ufficiale e KubernetesExecutor (lezione 55), che permettono a ogni task di girare nel proprio pod con il proprio budget di risorse e la propria container image.

Il lato non-così-buono: i DAG come file Python mescolano orchestrazione e logica. Lo scheduler fa il parse di ogni file DAG periodicamente, il che vuol dire che importare per sbaglio una libreria pesante in cima a un file DAG rallenta lo scheduler. I backfill (rieseguire un range di date con il codice più recente) erano dolorosi prima di Airflow 2.x e sono diventati pienamente ragionevoli solo dalla 2.3 in poi. La migrazione 1.x verso 2.x nel 2020 è stata vero lavoro di ingegneria per le shop che avevano costruito infrastruttura Airflow significativa.

L’installazione di Airflow è pesante per gli standard moderni. L’architettura di default ha un webserver, uno scheduler, un metadata database (Postgres o MySQL), un result backend, e un pool di worker (Celery, Kubernetes, o local). Far girare questa roba da soli sono diversi giorni di lavoro per farla bene e un onere di on-call continuo. La maggior parte delle shop nel 2026 o usa un Airflow managed (Astronomer, AWS MWAA, GCP Cloud Composer) o ha un platform team che lo mantiene come servizio condiviso.

Quando Airflow vince. Grandi organizzazioni che si erano già standardizzate su di lui. Shop che hanno bisogno dell’ecosistema di operator. Team le cui pipeline sono prevalentemente batch schedulati a tempo con DAG lunghi. Ovunque ci sia abbastanza scala da rendere “ancora un altro tool” una vendita più dura di “il tool esistente, usato bene”.

Prefect: la risposta sull’esperienza dello sviluppatore

Prefect è partito nel 2018 come risposta di Jeremiah Lowin alle frizioni che aveva incontrato facendo girare Airflow su scala. La linea 1.x era una reimmaginazione da zero; la linea 2.x (2022) è stata una riscrittura che ha semplificato ulteriormente il modello; la linea 3.x (2024) ha stretto di nuovo l’API. La feature in copertina è l’esperienza dello sviluppatore: i flow sono funzioni Python decorate, le dipendenze sono inferite da come le chiami, e l’API sembra più vicina allo scrivere Python normale che ad authorare un DAG.

from prefect import flow, task

@task
def extract():
    return load_from_source()

@task
def transform(rows):
    return clean(rows)

@flow
def daily_etl():
    rows = extract()
    cleaned = transform(rows)
    write_to_warehouse(cleaned)

Quello è un flow Prefect funzionante. La dipendenza tra extract e transform è implicita nel flusso dei dati. Non c’è un file DAG da registrare, non c’è una config separata di scheduler da scrivere. I flow dinamici (dove la forma del DAG dipende dai dati a runtime) sono first-class, cosa che Airflow supporta in modo goffo tramite la dynamic task mapping API mentre Prefect la gestisce nativamente.

Quando Prefect vince. Team più piccoli che danno valore all’esperienza dello sviluppatore. Pipeline la cui forma è dinamica (un fan-out su un numero ignoto di file, un flow per-cliente il cui conteggio varia di giorno in giorno). Team che vogliono un orchestrator managed con un free tier generoso e un onboarding a bassa frizione.

Il trade-off è un ecosistema più piccolo di Airflow. Prefect ha integrazioni per i tool dati principali, ma la lunga coda di operator di nicchia che Airflow ha accumulato in un decennio non c’è. La maggior parte dei team in pratica non ci sbatte; salta fuori ai margini.

Dagster: la risposta asset-oriented

Dagster, anche lui dal 2019, ha tirato uno schiaffo diverso. L’intuizione di base: gli orchestrator che pensano in task stanno mancando ciò di cui i data engineer si curano davvero, cioè gli asset che la pipeline produce. Un task è un mezzo per un fine. Il fine è la tabella customer, il revenue mart giornaliero, l’artefatto del modello addestrato. Quindi rendi l’asset l’unità dell’orchestrazione.

In Dagster, dichiari asset:

from dagster import asset

@asset
def raw_events():
    return load_from_kafka()

@asset
def sessionized_events(raw_events):
    return sessionize(raw_events)

@asset
def customer_lifetime_value(sessionized_events):
    return compute_clv(sessionized_events)

Le dipendenze tra asset si leggono dalle signature delle funzioni. Dagster costruisce il grafo degli asset automaticamente. Il lineage non è una cosa che aggiungi; è il modello. L’orchestrazione (quale task gira quando) è derivata dal grafo degli asset, non dichiarata separatamente.

Questo cambio, che la lezione 58 esplora in profondità, ha conseguenze. Il lineage arriva gratis. I modelli dbt sono asset first-class, non task opachi che l’orchestrator esegue. Input e output tipati permettono a Dagster di validare a runtime che un asset abbia davvero prodotto ciò che diceva di produrre. La UI mostra la freschezza dell’asset (“ultima materializzazione due ore fa”) invece del solo stato del task (“riuscito alle 02:14”).

Quando Dagster vince. Team che si curano di lineage, qualità del dato, e disciplina di software engineering applicata ai dati. Heavy user di dbt che vogliono il loro orchestrator e il loro tool di trasformazione condividere un vocabolario. Piattaforme nuove senza eredità di orchestrator dove il modello asset-oriented può essere adottato dal primo giorno.

I trade-off sono il buy-in concettuale (il team deve imparare a pensare in asset, non in task) e un ecosistema più piccolo di quello di Airflow, anche se il gap si è ristretto. Migrare una shop Airflow esistente verso Dagster è un progetto vero, non un weekend.

Argo Workflows: la risposta Kubernetes-native

Argo Workflows è quello strano della lista. Non è stato costruito principalmente per i dati; è stato costruito per Kubernetes. Ogni step in un workflow Argo è un pod. Il workflow stesso è una custom resource Kubernetes definita in YAML. L’orchestrator è un controller che osserva le risorse di workflow e le riconcilia, lo stesso pattern dello Spark Operator e del resto dell’ecosistema Kubernetes (lezione 55).

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  name: daily-etl
spec:
  entrypoint: pipeline
  templates:
    - name: pipeline
      dag:
        tasks:
          - name: extract
            template: extract-step
          - name: transform
            template: transform-step
            dependencies: [extract]

Argo è popolare per le pipeline ML (Kubeflow Pipelines è costruito su Argo) e per l’orchestrazione di workflow generici nelle shop che hanno commesso forte su Kubernetes. Scala a migliaia di pod concorrenti. È veloce, semplice, e si allinea bene con il resto di uno stack cloud-native.

Quando Argo vince. Team a forte componente ML che usano Kubeflow. Platform team che vogliono che il loro orchestrator si comporti come il resto di Kubernetes. Workload dominati da run di container brevi e paralleli piuttosto che da job batch long-lived con semantica dati ricca.

Il trade-off è YAML e un supporto più debole per le preoccupazioni specifiche dei dati. Argo non sa cosa sia una query Snowflake. Non ha un’integrazione dbt nativa. Il lineage è qualunque cosa tu ci appiccichi sopra. Per pipeline che sono per lo più “esegui questo Python in un container, poi esegui quell’altro”, Argo è ottimo. Per pipeline che sono per lo più “esegui questa trasformazione Snowflake, poi questo modello dbt, poi pubblica su BigQuery”, un orchestrator con integrazioni dati first-class è di solito un fit migliore.

Managed contro self-hosted

La scelta dell’orchestrator si intreccia, in pratica, con la scelta managed-contro-self-hosted. La maggior parte delle shop nel 2026 atterra su managed, e il ragionamento è coerente.

Self-hostare un orchestrator vuol dire far girare il suo metadata database (di solito Postgres), il suo scheduler, i suoi worker, la sua UI, la sua logica di retry, il suo log storage. Per Airflow è una mezza dozzina di componenti con le loro storie di scaling e upgrade. Per Prefect, Dagster, Argo, leggermente meno ma comunque reali. Chiunque abbia gestito gli upgrade di Airflow dalla 1.10 alla 2.x e poi dalla 2.x alla 2.7 conosce la tassa operativa.

Le offerte managed assorbono quella tassa in cambio di soldi: Astronomer (Airflow), Prefect Cloud, Dagster Cloud, Databricks Workflows (il loro orchestrator, si integra con i Databricks job), AWS MWAA (Airflow managed), GCP Cloud Composer (Airflow managed), Azure Data Factory (l’orchestrator di Microsoft). Il pricing varia, ma per la maggior parte dei team il conto è “paghiamo decine di migliaia all’anno, risparmiamo un mese-uomo all’anno di operazioni di cluster, e ci prendiamo un vendor da chiamare quando lo scheduler muore di domenica”.

Le eccezioni sono organizzazioni abbastanza grandi da poter dotarsi di un platform team dedicato che fa girare l’orchestrazione come servizio condiviso, e organizzazioni con vincoli regolatori che rendono dura una SaaS managed. Entrambe sono reali, entrambe comuni su scala, ed entrambe comportano scambiare soldi per controllo.

L’albero decisionale

Mettendo insieme i pezzi, l’albero decisionale grezzo che la maggior parte dei team percorre:

flowchart TD
    Q1{Pipeline complexity?}
    Q1 -->|Few jobs, simple deps| CRON[cron + scripts]
    Q1 -->|Real DAGs, real ops| Q2{Asset model fits?}
    Q2 -->|Yes, lineage matters| Q3a{Managed?}
    Q2 -->|No, task-oriented OK| Q3b{Existing tool?}
    Q3a -->|Yes| DC[Dagster Cloud]
    Q3a -->|No, want to host| DAGSTER[Self-host Dagster]
    Q3b -->|Yes, Airflow| Q4{Managed?}
    Q3b -->|No, fresh start| Q5{Style?}
    Q4 -->|Yes| AST[Astronomer/MWAA/Composer]
    Q4 -->|No| AF[Self-host Airflow]
    Q5 -->|Pythonic, dynamic| PRE[Prefect]
    Q5 -->|K8s-native, simple| ARGO[Argo Workflows]

Diagramma da creare: una versione rifinita dell’albero decisionale qui sopra, con i quattro orchestrator a foglia visivamente distinti. Il punto è che la scelta si divide pulitamente su tre assi (asset contro task, managed contro self-hosted, fit dell’ecosistema) e che tutte e quattro le foglie sono risposte difendibili per qualche team.

Lo stesso semplice ETL espresso in Airflow contro Dagster schizza la differenza. Airflow:

with DAG("daily_etl", schedule="@daily") 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

Dagster:

@asset
def raw_data():
    return extract()

@asset
def cleaned_data(raw_data):
    return transform(raw_data)

@asset
def warehouse_table(cleaned_data):
    return load(cleaned_data)

Stessa pipeline, modelli mentali diversi. Airflow è “esegui questi task in ordine secondo questo schedule”. Dagster è “questi sono gli asset che produci; capisci tu come tenerli freschi”. La prossima lezione parla del perché quel secondo framing cambia il modo in cui i team pensano su scala.

Cosa ha allestito questa lezione

Il lavoro del Modulo 8 è prendere l’architettura che gira e renderla operabile: orchestrazione (questa lezione), framing asset-oriented (lezione successiva), osservabilità (lezione 59), pratiche di affidabilità (il resto del modulo). L’orchestrator è la spina dorsale. La scelta che fai qui si propaga in ogni altra decisione: come strumenti il lineage, come gestisci i retry, come definisci una SLO per un data product. Scegliere deliberatamente vale il tempo speso.

Per la maggior parte delle shop dati medio-grandi nel 2026, la risposta pratica è una tra: Airflow managed se hai un’eredità Airflow, Dagster Cloud se stai partendo da zero e ti curi dei data product, Prefect Cloud se vuoi l’esperienza dello sviluppatore e hai workflow dinamici, Argo se la tua piattaforma è Kubernetes-first e i tuoi workload hanno forma di container. Tutte e quattro vanno bene. Quella che si allinea al modello mentale del tuo team e alla tua infrastruttura esistente è quasi sempre quella giusta.

Riferimenti e approfondimenti

  • Apache Airflow documentation, https://airflow.apache.org/docs/ (consultato 2026-05-01). Il riferimento ufficiale per l’orchestrator originale, il suo catalogo di operator, e le integrazioni Kubernetes.
  • Prefect documentation, https://docs.prefect.io/ (consultato 2026-05-01). I docs della 3.x coprono flow, task, deployment, e il modello di esecuzione ibrido.
  • Dagster documentation, https://docs.dagster.io/ (consultato 2026-05-01). Il modello asset-oriented è il cuore dei docs; le integrazioni dbt e Snowflake sono utili punti di partenza.
  • Argo Workflows documentation, https://argo-workflows.readthedocs.io/ (consultato 2026-05-01). Il workflow engine Kubernetes-native, con i riferimenti su YAML e sul pattern degli operator.
  • Maxime Beauchemin, “The Rise of the Data Engineer” e gli annunci originali di Airflow sul blog di engineering di Medium (dal 2017 in poi). Contesto utile sul perché Airflow esiste nella forma in cui esiste.
Cerca