Zurück zur Startseite

Jobify: asyncio-Planer ohne Broker

Jobify — asynchroner Aufgabenplaner für Python ohne externe Infrastruktur. Verwendet SQLite für Persistenz, Middleware für Erweiterung, API im FastAPI-Stil. Geeignet für Middle/Senior-Entwickler, die leichte Kontrolle über den Aufgabenlebenszyklus benötigen.

Hintergrundaufgaben mit Jobify erstellen ohne Celery
Advertisement 728x90

Jobify: Ein asynchroner Task-Scheduler ohne externe Infrastruktur

Jobify ermöglicht es Ihnen, einen asynchronen Task-Scheduler mit nur wenigen Codezeilen einzurichten. Keine Message-Broker erforderlich, mit SQLite als Standard für Persistenz. Tasks werden auf der Festplatte gespeichert und überstehen Anwendungsneustarts.

Grundlegendes Beispiel:

import asyncio
from jobify import Jobify

app = Jobify()


@app.task
async def send_notification(user_id: int) -> None:
    print(f"Benutzer {user_id} benachrichtigen")


async def main() -> None:
    async with app:
        await send_notification.push(42)
        print("Job im Hintergrund geplant")


asyncio.run(main())

Die Methode push() reiht einen Task im Hintergrund ein, ohne zu blockieren. Jobify verwendet loop.call_at für präzise Zeitsteuerung anstelle einer Abfrageschleife, was die Leerlauflast reduziert.

Google AdInline article slot

Skalierungsherausforderungen mit Hintergrundtasks

Mit steigender Anzahl von Tasks stoßen einfache Lösungen an ihre Grenzen. Die Standardbibliothek sched eignet sich nur für synchrone verzögerte Aufrufe ohne Persistenz und Wiederholungsversuche.

Linux cron ist ideal für Systemskripte, integriert sich aber nicht in Ihre Anwendung. Celery erfordert Broker (RabbitMQ/Redis) und Infrastruktur. APScheduler kommt näher, schränkt aber die Task-Lebenszyklusverwaltung ein.

Jobify löst dies durch:

Google AdInline article slot
  • Vollständigen Task-Lebenszyklus: Status, Wiederholungen, Timeouts
  • Middleware für Ausführung und Planung (äußere Middleware)
  • Dependency Injection über Lifespan
  • Automatische Task-Deduplizierung
  • Native asyncio-Unterstützung

FastAPI-ähnliche API

FastAPI-Entwickler werden Jobify schnell verstehen. Vertraute Konzepte umfassen:

  • Task-Dekoratoren @app.task
  • Lifespan für Zustandsinitialisierung
  • Middleware-Stack
  • Zustandsinjektion via INJECT

Beispiel mit Ergebniswarte:

import asyncio
from jobify import Jobify

app = Jobify()


@app.task
async def send_email(to: str, subject: str) -> None:
    print(f"E-Mail an {to} senden: {subject}")


async def main() -> None:
    async with app:
        job = await send_email.schedule(
            to="[email protected]",
            subject="Willkommen!",
        ).delay(10)
        await job.wait()


asyncio.run(main())

Das Job-Objekt bietet Zugriff auf Status, Ergebnis und Abbruch.

Google AdInline article slot

Lifespan und Dependency Injection

Konfiguration über Lifespan:

import asyncio
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from jobify import INJECT, Jobify, State


@asynccontextmanager
async def lifespan(_: Jobify) -> AsyncIterator[dict[str, str]]:
    yield {"sender": "[email protected]"}


app = Jobify(lifespan=lifespan)


@app.task
def send_email(to: str, subject: str, state: State = INJECT) -> None:
    print(f"{state.sender} -> {to}: {subject}")

Ausführungsrichtlinien werden im Dekorator festgelegt:

@app.task(retry=3, timeout=30)
async def sync_user(user_id: int) -> None:
    # ...

Middleware: Verwaltung von Planung und Ausführung

Äußere Middleware wird ausgelöst, wenn ein Task in die Warteschlange gestellt wird:

import asyncio
from jobify import Jobify, OuterContext
from jobify.middleware import BaseOuterMiddleware, CallNextOuter


class ScheduleLoggerMiddleware(BaseOuterMiddleware):
    async def __call__(
        self,
        call_next: CallNextOuter,
        context: OuterContext,
    ) -> asyncio.Handle:
        print(f"Planung von {context.job.id} mit Trigger: {context.trigger}")
        return await call_next(context)


app = Jobify(outer_middleware=[ScheduleLoggerMiddleware()])

Reguläre Middleware erweitern die Ausführung (Protokollierung, Metriken, Wiederholungen).

Abfragefreie Architektur

Jobify vermeidet while True: sleep(1): check_tasks(). Jeder Task wird sofort über loop.call_at für einen genauen Zeitpunkt registriert.

Vorteile:

  • Keine Leerlauflast
  • Präzise Zeitsteuerung
  • Blockiert nicht den Event-Loop

Kompromiss: Abhängigkeit von monotoner Zeit. Bei Systemzeitrücksetzung müssen Tasks neu berechnet werden.

Hauptmerkmale

  • Persistenz: SQLite standardmäßig, Tasks überstehen Neustarts
  • Deduplizierung: automatische Verhinderung von Duplikaten durch ID
  • Middleware-Stack: Eingriff in Planung und Ausführung
  • FastAPI-ähnliche API: minimale Lernkurve für vertraute Entwickler
  • Leichtgewichtig: keine Broker, Worker oder externen Abhängigkeiten

— Editorial Team

Advertisement 728x90

Weiterlesen