3 Punkte von GN⁺ 2026-01-30 | Noch keine Kommentare. | Auf WhatsApp teilen
  • Oban.py ist eine auf PostgreSQL basierende Portierung von Elixirs Job-Verarbeitungs-Framework Oban nach Python, mit der Jobs allein über die Datenbank eingefügt und verarbeitet werden können
  • Jobs werden innerhalb von Datenbanktransaktionen erstellt und zurückgerollt; unterstützt werden unter anderem Queue-Management, Ergebnisspeicherung und Cron-Scheduling
  • Die Open-Source-Version hat Einschränkungen wie Single-Thread-asyncio-Ausführung und individuelles Einfügen und Bestätigen, während die Pro-Version Parallelverarbeitung, Workflows und Smart Concurrency bietet
  • Der interne Ablauf besteht aus fünf Schritten: Insert → Notify → Fetch → Execute → Ack; dabei wird PostgreSQLs FOR UPDATE SKIP LOCKED genutzt, um Konflikte bei der Parallelität zu vermeiden
  • Leader Election, Wiederherstellung verwaister Jobs und Backoff-Retries werden ebenfalls datenbankbasiert ausgeführt und ermöglichen so eine stabile verteilte Verarbeitung ohne externen Broker

Überblick über Oban.py

  • Oban.py ist eine nach Python portierte, datenbankbasierte Job-Verarbeitungs-Framework-Variante von Elixirs Oban
    • Jobs werden innerhalb von Datenbanktransaktionen eingefügt und verarbeitet; bei Fehlern wird die gesamte Transaktion zurückgerollt
    • Enthält verschiedene Steuerungsfunktionen wie Queue-Limits, Speicherung abgeschlossener Jobs, Ergebnisaufbewahrung und Cron-Scheduling
  • Es gibt zwei Versionen
    • Open Source (OSS): Single-Thread-asyncio-Ausführung, individuelles Einfügen und Bestätigen, einfache Wiederherstellung
    • Pro-Version: Parallelverarbeitung auf Basis eines Prozesspools, Unterstützung für Workflows, Relays, Unique Jobs und Smart Concurrency
  • OSS eignet sich für persönliche Projekte oder Evaluierungen, für große Umgebungen wird die Pro-Version empfohlen

Pfad der Job-Verarbeitung

  • Nach dem Einfügen werden Jobs in der Tabelle oban_jobs mit state='available' gespeichert, und per PostgreSQL-NOTIFY wird eine Benachrichtigung an jeden Knoten gesendet
  • Der Stager jedes Knotens erkennt die betreffende Queue und weckt den Producer auf, der die Jobs abholt und ausführt
  • Bei der Job-Auswahl wird SQLs FOR UPDATE SKIP LOCKED verwendet, um parallele Verarbeitung ohne doppelte Ausführung zu ermöglichen
    • Bereits gesperrte Zeilen werden übersprungen, sodass andere Producer sofort andere Jobs holen können
  • Jobs werden als Async-Tasks dispatcht; nach Abschluss erfolgt die Acknowledgement-Verarbeitung per Callback
  • Die Pro-Version verwendet statt asyncio einen Prozesspool-Dispatcher und unterstützt so parallele Ausführung über mehrere CPU-Kerne

Hintergrundprozesse

  • Leader Election
    • Der Leader wird über PostgreSQLs INSERT ... ON CONFLICT und ein lease-basiertes TTL-Verfahren bestimmt
    • Ohne separates Konsensprotokoll übernimmt ein einzelner Leader das Aufräumen und Wiederherstellen von Jobs
  • Lifeline (Wiederherstellung verwaister Jobs)
    • Läuft ein Job länger als eine bestimmte Zeit (rescue_after, standardmäßig 5 Minuten), wird er in den Status available zurückversetzt
    • Die Pro-Version prüft, ob der Producer noch lebt, OSS entscheidet nur zeitbasiert
  • Pruner (Job-Bereinigung)
    • Löscht abgeschlossene, abgebrochene oder verworfene Jobs, deren max_age (standardmäßig 1 Tag) überschritten ist
    • Begrenzt den Löschumfang mit LIMIT, um Datenbanklast zu vermeiden

Retries und Backoff

  • Wenn ein Job eine Ausnahme auslöst, entscheidet der Executor, ob ein Retry erfolgt
    • Liegt die Zahl unter der maximalen Anzahl an Versuchen (max_attempts), wird erneut versucht, andernfalls wird der Job verworfen
  • Der Standard-Backoff ist ein exponentieller Anstieg mit Jitter
    • Verhindert bei vielen Fehlschlägen gleichzeitige Retries und mildert so Lastspitzen durch den Thundering Herd
    • Beispiel: ca. 17 Sekunden beim 1. Versuch, ca. 47 Sekunden beim 5. Versuch, ca. 17 Minuten beim 10. Versuch
  • Worker-Klassen können über die Methode backoff() eine benutzerdefinierte Backoff-Logik implementieren

Wichtige Merkmale und Bewertung

  • PostgreSQL übernimmt die Schlüsselrolle
    • Über FOR UPDATE SKIP LOCKED, LISTEN/NOTIFY und ON CONFLICT werden Parallelitätskontrolle, Signalisierung und Leader Election vollständig umgesetzt
    • Statt Redis oder eines externen Brokers wird eine einzelne Datenbank als Koordinationsschicht genutzt
  • Nicht parallel, aber nebenläufig
    • Auf asyncio basierend und damit gut für I/O-bound Workloads geeignet; für CPU-bound Aufgaben wird die Pro-Version empfohlen
  • Klare Code-Struktur
    • Konsistente Benennung und sauber getrennte Verantwortlichkeiten sorgen für eine gut lesbare Codebasis
  • Klare Rollentrennung zwischen OSS und Pro
    • OSS für Experimente und kleinere Einsätze, Pro für große Umgebungen und hohe Performance
  • Fazit: Eine saubere und strukturiert umgesetzte Python-Portierung, die allein mit PostgreSQL eine vollständige Job-Queue implementiert, und geeignet ist für Elixir-Nutzer oder Entwickler, die ein Job-System ohne externe Infrastruktur suchen

Noch keine Kommentare.

Noch keine Kommentare.