azout: Azure-Datenprodukte im Terminal
Ein Ratatui-TUI für das Monitoring von Pipelines, Spark Pools und mehr
- azure
- cli
- monitoring
- rust
- tui
Das Azure Portal ist langsam. Drei Klicks bis zur Pipeline-Übersicht, fünf bis zu den Activity-Details, und bei jedem Refresh lädt die gesamte Seite neu. Bei 20+ Pipeline-Runs pro Tag wird das zum Produktivitätskiller. azout löst das: ein Terminal-UI das alle Azure-Datenprodukte auf einen Blick zeigt — Synapse Pipelines, Spark Pools, Azure DevOps Integration, und perspektivisch Container Apps und Functions.
Was azout zeigt
Das TUI hat zwei Hauptbereiche:
Pipeline-Tabelle: Alle Runs der letzten N Stunden — Name, Status (farbkodiert), Dauer, Start/Ende, Bundesland-Kürzel (extrahiert aus den Pipeline-Parametern). Filtert nach Status (Running/Succeeded/Failed/Cancelled), durchsucht Pipeline-Namen und Parameter-JSON, sortiert nach 10 verschiedenen Spalten.
Spark-Pool-Panel: Kapazität (vCores/Memory), aktive Sessions und Batches, Auto-Scale-Konfiguration, Auslastung in Prozent. Die Metriken kommen direkt aus Azure Monitor — nicht nur statische Pool-Config, sondern tatsächlich allokierte Ressourcen.
Non-Blocking Architecture
Das Kernproblem bei TUI-Tools: API-Calls dauern Sekunden. Wenn das UI dabei einfriert, ist das Tool wertlos. azout löst das mit einer strikten Trennung:
// Background-Task für API-Calls
let tx = result_tx.clone();
let synapse = synapse.clone();
tokio::spawn(async move {
let (runs, pools) = tokio::join!(
synapse.list_pipeline_runs(hours),
synapse.fetch_spark_pool_status()
);
let _ = tx.send(BackgroundResult::Refresh { runs, pools }).await;
});
Alle API-Calls laufen in Tokio-Tasks. Die Event Loop bleibt frei für Keyboard-Input und Rendering. Ein animierter Spinner zeigt den Ladezustand. Navigation, Filterung und Sortierung funktionieren auch während des Ladens.
Pending-Operations werden getrackt um doppelte Requests zu vermeiden:
pub pending_activity_load: Option<(String, String)>,
pub pending_spark_jobs_load: Option<String>,
pub pending_cancel: Option<String>,
State Machine statt Spaghetti
Jeder Screen ist ein expliziter App-Modus:
pub enum AppMode {
Normal, // Pipeline-Tabelle
Filter, // Textsuche
Help, // Hilfe-Popup
ActivityView, // Drill-Down in Pipeline-Activities
HistoryComparison, // Laufzeit-Vergleich über Runs
SparkJobsView, // Spark Sessions/Batches
}
Jeder Modus hat einen dedizierten Event-Handler. Kein verschachteltes if/else, kein globaler State der sich gegenseitig beeinflusst.
Desktop Notifications
azout benachrichtigt per Desktop-Notification wenn Pipelines fertig werden — aber intelligent:
- Nur Pipelines die nach App-Start begonnen haben lösen Notifications aus
HashSet<run_id>verhindert Duplikate- Fast-Finish-Erkennung: Pipelines die innerhalb eines Refresh-Zyklus (30s) starten und enden werden trotzdem erkannt
- Separat konfigurierbar für Success und Failure
Das klingt trivial, war es aber nicht. Ohne Launch-Time-Tracking kamen beim Erweitern des Zeitfensters (z.B. von 24h auf 48h) falsche Notifications für alte Runs.
Drill-Down: Activities und History
Enter auf einem Run zeigt alle Activities — die einzelnen Schritte einer Pipeline. Typ (DataFlow, Copy, ExecutePipeline), Status, Dauer, Fehlermeldungen. Pagination via Continuation Tokens für große Pipelines.
Space zeigt den Laufzeit-Verlauf: alle Runs derselben Pipeline, sortiert nach Startzeit, mit Duration-Deltas. Sofort sichtbar ob ein Run langsamer wurde.
o öffnet den Run direkt im Azure Portal — die korrekte Workspace-URL wird automatisch zusammengebaut.
Bundesland-Erkennung
Unsere Pipelines verarbeiten Geodaten pro Bundesland. azout extrahiert das Kürzel aus den Pipeline-Parametern und färbt es ein:
"bayern" | "bavaria" => Some(("BY", Color::Rgb(0, 125, 182))),
"mecklenburg-vorpommern" | "mecklenburg vorpommern"
| "mecklenburg_vorpommern"
| "mecklenburg-western pomerania" => Some(("MV", Color::Rgb(0, 85, 164))),
Alle 16 Bundesländer mit Varianten (Bindestriche, Unterstriche, Leerzeichen, englische Namen). Auf einen Blick sichtbar welches Bundesland gerade läuft.
Keyboard-First
j/k oder Pfeile Navigation
/ Filter
Tab Status-Filter wechseln
s Sortierung wechseln
Enter Activity-Details / Spark-Jobs
Space Laufzeit-Vergleich
c Pipeline abbrechen
R Manueller Refresh
a Auto-Refresh togglen
n Notifications togglen
b Spark-Panel ein/ausblenden
` Fokus zwischen Panels wechseln
+/- Zeitfenster anpassen
o Im Browser öffnen
Tech Stack
- Rust mit Tokio (async, multi-threaded)
- Ratatui für das Terminal-UI
- Azure SDK (
azure_identity,azure_core) mit DefaultAzureCredential - Crossterm für Terminal-Kontrolle
- notify-rust für Desktop-Notifications
- rusqlite (bundled) für lokale History
Was es spart
Vorher: Azure Portal öffnen, zur Synapse-Instanz navigieren, Monitor-Tab, Pipeline-Runs filtern, auf einen Run klicken, Activities laden. Pro Check ~30 Sekunden, 20x am Tag = 10 Minuten reines Warten.
Jetzt: Terminal ist offen, azout läuft. Alles auf einen Blick, Auto-Refresh alle 30 Sekunden, Notification wenn etwas fertig wird oder fehlschlägt. Die eingesparte Zeit summiert sich.