
CI/CD for data pipelines
Implement CI/CD for dbt, Airflow, and ETL: automated tests, isolated environments, safe deploys.
What you will learn
- Configurare una pipeline CI/CD per dbt con build sui modelli modificati e schema isolato
- Preparare staging obbligatorio, canarino su frazione dei dati e rollback atomico prima del deploy
CI/CD for data pipelines
Questa lezione, sul binario ml-tabellare, ti abitua a una verità scomoda: nelle pipeline dati i difetti non si vedono quando li commetti, ma quando qualcun altro legge la dashboard. La CI/CD serve esattamente a questo.
Che cosa significa CI/CD applicata ai dati
La CI/CD per dati blocca modelli difettosi in isolamento con test automatici prima del rilascio in produzione. In una frase: il codice sbagliato non deve mai avere la possibilità di arrivare dove decide qualcuno.
Il flusso del rilascio
- Isola ogni modifica in branch e schema di sviluppo separato dalla produzione.
- Esegui build e test automatici sui soli modelli modificati a ogni pull request.
- Valida in staging per 24 ore prima di promuovere in produzione.
- Prepara rollback atomico con revert e rebuild prima di ogni deploy.
Cinque regole che separano un rilascio sicuro da uno manuale
Ogni analista lavora sul proprio schema di sviluppo e mai direttamente su produzione. A ogni pull request scatta una build automatica: se la build fallisce, la modifica non si fonde. Il deploy è progressivo con staging obbligatorio e validazione prima della produzione. Il rollback usa revert Git e rebuild oppure scambio immediato tra ambienti. Infine, la qualità vive dentro la pipeline con test su valori nulli, unicità e valori ammessi che bloccano la fusione se falliscono.
Verdetto: branch isolato, build sui modificati e staging obbligatorio; senza questi tre il rilascio resta manuale.
GitHub Actions configuration for dbt
name: dbt CI
on:
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
environment: ci
steps:
- uses: actions/checkout@v3
- name: Install dbt
run: pip install dbt-snowflake
- name: Build modified models
env:
SNOWFLAKE_USER: ${{ secrets.SNOWFLAKE_USER }}
SNOWFLAKE_PASSWORD: ${{ secrets.SNOWFLAKE_PASSWORD }}
run: |
dbt deps
dbt build --select state:modified+ --target ci \
--defer --state ./target/
Il flag con stato differito esegue solo i modelli modificati e prende il resto dalla produzione. La pipeline passa da ore a minuti senza perdere copertura.
Orchestrazione, test e canarino
I DAG restano codice versionato con ambienti separati tra sviluppo, staging e produzione. Prima del rilascio i flussi girano in modalità test su dati sintetici. Le modifiche delicate partono su una frazione dei dati con verifica dell’output e poi scalano al totale. Il lineage è il grafo delle dipendenze tra tabelle: lo dichiari per far sì che un cambiamento non rompa tabelle a valle in silenzio.
Verdetto: test su sintetici e canarino su frazione dei dati prima del totale.
SQL example: building a control view
Il pattern crea una base analitica con metrica, segmento e finestra temporale. Così confronti periodi e gruppi senza riscrivere la logica.
WITH base_events AS (
SELECT
user_id,
account_id,
event_type,
event_time,
DATE_TRUNC('week', event_time) AS week,
source,
device_type
FROM events
WHERE event_time >= CURRENT_DATE - INTERVAL '180 days'
AND user_id IS NOT NULL
),
weekly_user_metrics AS (
SELECT
week,
user_id,
COALESCE(source, 'unknown') AS source,
COALESCE(device_type, 'unknown') AS device_type,
COUNT(*) AS total_events,
COUNT(DISTINCT DATE(event_time)) AS active_days,
COUNT(DISTINCT event_type) AS event_diversity,
MAX(CASE WHEN event_type IN ('purchase', 'subscribe', 'activation') THEN 1 ELSE 0 END) AS reached_key_outcome
FROM base_events
GROUP BY week, user_id, source, device_type
)
SELECT
week,
source,
device_type,
COUNT(DISTINCT user_id) AS users,
ROUND(AVG(active_days), 2) AS avg_active_days,
ROUND(AVG(event_diversity), 2) AS avg_event_diversity,
ROUND(AVG(reached_key_outcome) * 100, 2) AS key_outcome_rate
FROM weekly_user_metrics
GROUP BY week, source, device_type
ORDER BY week, source, device_type;
Python example: checking stability and anomalies
Il controllo su finestra mobile segnala le variazioni che meritano indagine dopo ogni deploy.
# df contiene: week, segment, users, key_outcome_rate
# key_outcome_rate espresso in percentuale, es. 12.4
df = df.sort_values(['segment', 'week']).copy()
df['previous_rate'] = df.groupby('segment')['key_outcome_rate'].shift(1)
df['wow_change_pp'] = df['key_outcome_rate'] - df['previous_rate']
df['rolling_mean'] = df.groupby('segment')['key_outcome_rate'].transform(
lambda s: s.rolling(4, min_periods=2).mean()
)
df['rolling_std'] = df.groupby('segment')['key_outcome_rate'].transform(
lambda s: s.rolling(4, min_periods=2).std()
)
df['z_score'] = (df['key_outcome_rate'] - df['rolling_mean']) / df['rolling_std']
anomalies = df[df['z_score'].abs() >= 2].sort_values('z_score')
print(anomalies[['week', 'segment', 'key_outcome_rate', 'wow_change_pp', 'z_score']])
Quando un aggiornamento fermò mezzo mondo
Il 19 luglio 2024 un aggiornamento difettoso del sensore CrowdStrike Falcon manda in boot loop circa 8,5 milioni di PC Windows nel mondo. Il file viene distribuito senza rilascio graduale e senza blocco automatico, così compagnie aeree, banche e ospedali restano fermi per ore. Il ripristino richiede intervento manuale su ogni macchina colpita. La lezione per la CI/CD dati è identica: nessun artefatto tocca la produzione senza canarino, test e rollback pronto.
Domande per controllare il tuo processo
- Quale test blocca la tua pull request se un modello è difettoso?
- Quale ambiente isolato separa sviluppo, staging e produzione?
- Quale strategia di rollback applichi se il deploy fallisce?
- Quale controllo verifica l’output prima di scalare al totale?
Bloccato su questo argomento o vuoi applicarlo al tuo caso? Prenota una call di 15 minuti con un analista esperto.
Related Path
Lessons to read together
Questi collegamenti portano la lezione dentro il resto del corso: basi da riprendere, passaggi successivi e connessioni tematiche tra moduli.