Diese Lektion verdrahtet alles miteinander: Ingestion, Silver, Features, ML-Inferenz und Gold — orchestriert als ein einziger produktiver Workflow. Am Ende weißt du, wie du Task-Abhängigkeiten strukturierst, Fehler sauber abfängst, Retries konfigurierst und das Alerting für deine Wetter-zu-Strom-Pipeline aufsetzt.
Databricks Workflows werden als JSON definiert (alternativ über die UI oder Terraform). So sieht die Struktur für deine Pipeline aus:[1]
{
"name": "weather-to-power-pipeline",
"schedule": {
"quartz_cron_expression": "0 0 5,11,17,23 * * ?",
"timezone_id": "UTC"
},
"tasks": [
{
"task_key": "ingest_ecmwf",
"notebook_task": { "notebook_path": "/pipelines/ingest_ecmwf" },
"job_cluster_key": "ingest_cluster",
"timeout_seconds": 1800,
"retry_on_timeout": true,
"max_retries": 2
},
{
"task_key": "ingest_gfs",
"notebook_task": { "notebook_path": "/pipelines/ingest_gfs" },
"job_cluster_key": "ingest_cluster",
"max_retries": 2
},
{
"task_key": "ingest_icon",
"notebook_task": { "notebook_path": "/pipelines/ingest_icon" },
"job_cluster_key": "ingest_cluster",
"max_retries": 2
},
{
"task_key": "ingest_telemetry",
"notebook_task": { "notebook_path": "/pipelines/ingest_telemetry" },
"job_cluster_key": "ingest_cluster",
"max_retries": 2
},
{
"task_key": "silver_weather",
"depends_on": [
{"task_key": "ingest_ecmwf"},
{"task_key": "ingest_gfs"},
{"task_key": "ingest_icon"}
],
"notebook_task": { "notebook_path": "/pipelines/bronze_to_silver_weather" },
"job_cluster_key": "transform_cluster"
},
{
"task_key": "silver_telemetry",
"depends_on": [{"task_key": "ingest_telemetry"}],
"notebook_task": { "notebook_path": "/pipelines/bronze_to_silver_telemetry" },
"job_cluster_key": "transform_cluster"
},
{
"task_key": "compute_features",
"depends_on": [
{"task_key": "silver_weather"},
{"task_key": "silver_telemetry"}
],
"notebook_task": { "notebook_path": "/pipelines/compute_features" },
"job_cluster_key": "transform_cluster"
},
{
"task_key": "ml_inference",
"depends_on": [{"task_key": "compute_features"}],
"notebook_task": { "notebook_path": "/pipelines/ml_inference" },
"job_cluster_key": "ml_cluster"
},
{
"task_key": "write_gold",
"depends_on": [{"task_key": "ml_inference"}],
"notebook_task": { "notebook_path": "/pipelines/write_gold" },
"job_cluster_key": "transform_cluster"
}
],
"job_clusters": [
{
"job_cluster_key": "ingest_cluster",
"new_cluster": {
"num_workers": 0,
"spark_version": "14.3.x-scala2.12",
"node_type_id": "Standard_E4s_v3",
"init_scripts": [{"dbfs": {"destination": "dbfs:/init/install_cfgrib.sh"}}]
}
},
{
"job_cluster_key": "transform_cluster",
"new_cluster": {
"num_workers": 2,
"spark_version": "14.3.x-scala2.12",
"node_type_id": "Standard_D4s_v3"
}
},
{
"job_cluster_key": "ml_cluster",
"new_cluster": {
"num_workers": 1,
"spark_version": "14.3.x-ml-scala2.12",
"node_type_id": "Standard_E8s_v3"
}
}
],
"email_notifications": {
"on_failure": ["team@company.com"],
"on_duration_warning_threshold_exceeded": ["team@company.com"]
},
"health": {
"rules": [
{"metric": "RUN_DURATION_SECONDS", "op": "GREATER_THAN", "value": 3600}
]
}
}
Tasks mit demselben job_cluster_key nutzen denselben Cluster — er bleibt zwischen den Tasks am Leben. Das spart Startzeit (ca. 3–5 Min. pro Cluster), bedeutet aber, dass du die Leerlaufzeit zwischen aufeinanderfolgenden Tasks bezahlst.
| Strategie | Wann |
|---|---|
| Gemeinsamer Cluster (gleicher job_cluster_key) | Sequenzielle Tasks mit denselben Bibliotheksanforderungen |
| Getrennte Cluster | Andere Runtime nötig (z. B. ML vs. Standard) oder starke Parallelität |
| Single-Node (num_workers: 0) | I/O-lastige Tasks wie API-Downloads und GRIB-Parsing |
// Standard: ALLE Vorgänger müssen erfolgreich sein
"depends_on": [{"task_key": "ingest_ecmwf"}, {"task_key": "ingest_gfs"}]
// Wenn eine Quelle optional ist (z. B. ICON als Nice-to-have):
// "run_if"-Bedingung nutzen oder den optionalen Pfad abtrennen
"run_if": "ALL_SUCCESS" // Standard
"run_if": "AT_LEAST_ONE_SUCCESS" // wenn Teildaten akzeptabel sind
Wetterquellen sind unterschiedlich zuverlässig. ECMWF ist womöglich kritisch (ohne diese Quelle scheitert die Pipeline), während ICON nur ergänzt. Entwirf die Abhängigkeiten so, dass: (1) ein ECMWF-Ausfall die Pipeline blockiert, (2) ein ICON-Ausfall eine Warnung protokolliert, die Pipeline aber allein mit ECMWF- und GFS-Daten weiterläuft.
{
"max_retries": 2, // insgesamt 3 Versuche
"min_retry_interval_millis": 60000, // 1 Min. Pause zwischen den Versuchen
"retry_on_timeout": true // auch bei Timeout erneut versuchen
}
Retries sind bei vorübergehenden Störungen sinnvoll (API-Timeout, verdrängte Spot-Instanz). Sie sind es nicht bei Logikfehlern (fehlerhafter Code) oder bei Datenqualitätsproblemen — die gehören gemeldet, nicht wiederholt.
Der Zeitplan deiner Pipeline muss zur Verfügbarkeit der Wettermodelle passen:
| Modell | Initialisierungszeiten | Verfügbar ab | Dein Trigger |
|---|---|---|---|
| ECMWF | 00, 06, 12, 18 UTC | Init + 5–6 h | 05, 11, 17, 23 UTC |
| GFS | 00, 06, 12, 18 UTC | Init + 3,5–4 h | (gleicher Trigger, läuft früher) |
| ICON | 00, 06, 12, 18 UTC | Init + 2–3 h | (gleicher Trigger, läuft früher) |
# Cron: 4× täglich, 5 Stunden nach der Modell-Initialisierung
# "0 0 5,11,17,23 * * ?" = um 05:00, 11:00, 17:00 und 23:00 UTC
"quartz_cron_expression": "0 0 5,11,17,23 * * ?"
# Letzter Task im Workflow: Ausgabe der Pipeline validieren
from datetime import datetime, timedelta, timezone
def validate_pipeline_output():
"""Assert that Gold table has fresh data after pipeline completes."""
latest_gold = spark.sql("""
SELECT MAX(produced_at) as latest
FROM prod.gold.forecast_ts
""").collect()[0]["latest"]
threshold = datetime.now(timezone.utc) - timedelta(hours=2)
assert latest_gold >= threshold, \
f"Gold data stale! Latest: {latest_gold}, expected >= {threshold}"
# Prüfen, ob alle Parks Prognosen haben
parks_with_forecasts = spark.sql("""
SELECT COUNT(DISTINCT asset_id)
FROM prod.gold.forecast_ts
WHERE produced_at > current_timestamp() - INTERVAL 2 HOURS
AND asset_type = 'wind_park'
""").collect()[0][0]
expected_parks = spark.sql("""
SELECT COUNT(*) FROM prod.silver.dim_assets
WHERE asset_type = 'wind_park'
""").collect()[0][0]
assert parks_with_forecasts == expected_parks, \
f"Missing parks! Got {parks_with_forecasts}/{expected_parks}"
print(f"✓ Pipeline validation passed: {parks_with_forecasts} parks forecasted")
Konfiguriere Workflows nicht von Hand in der UI. Nutze Infrastructure as Code, damit alles reproduzierbar bleibt:
| Werkzeug | Wann | Databricks-Unterstützung |
|---|---|---|
| Databricks Asset Bundles (DABs) | Standardwahl für Databricks-native Projekte | First-Party, YAML-basiert, inklusive CI/CD-Vorlagen |
| Terraform | Multi-Cloud, bestehendes Terraform-Ökosystem | Offizieller Provider: databricks/databricks |
| REST API + Skripte | Schnelle Automatisierung, eigenes Tooling | Vollständige Jobs-API |
DABs sind der Databricks-eigene Weg, Workflows, Notebooks und Konfiguration zu paketieren. Sie unterstützen Dev-/Staging-/Prod-Umgebungen, integrieren sich in CI/CD (GitHub Actions, Azure DevOps) und regeln die Promotion zwischen Umgebungen. Starte hier — es sei denn, deine Organisation ist bereits durchgehend Terraform-getrieben.
Der Silver-Task für Wetter hängt von allen drei Ingestion-Tasks ab (ECMWF, GFS, ICON). Die ICON-Ingestion scheitert. Was sollte passieren?
Warum getrennte Job-Cluster für Ingestion (Single-Node) und Transformation (Multi-Node)?
Deine Pipeline läuft täglich um 05:00 UTC. Bisher war sie nach 25 Minuten fertig. Heute brauchte sie 90 Minuten. Welcher Mechanismus erkennt das?
"metric": "RUN_DURATION_SECONDS", "op": "GREATER_THAN", "value": 3600 löst aus, sobald der Workflow eine Stunde überschreitet. So fängst du Performance-Regressionen, unerwartet große Datenmengen oder Ressourcenengpässe ab — selbst dann, wenn die Pipeline am Ende erfolgreich durchläuft.📖 Empfohlene Lektüre
Dokumentation zu Databricks Workflows — behandelt Task-Typen, Abhängigkeiten, Cluster-Konfiguration, Zeitpläne und Monitoring. Sieh dir außerdem Databricks Asset Bundles für Deployments per Infrastructure as Code an.
Die Pipeline ist vollständig orchestriert. Die letzte Lektion behandelt Kosten, Performance & Betrieb — Cluster effizient dimensionieren, Ausgaben steuern, Delta-Tabellen optimieren und Runbooks für den Produktivbetrieb schreiben.
Fragen zu Setups mit mehreren Workflows, zum Auslösen von Pipelines durch externe Events oder zur CI/CD-Integration? Frag deinen Lehrer.
Rechtliches: Impressum