Kurzantwort
Nicht alles, was Ihre App tut, kann passieren, während ein Nutzer auf einen Ladespinner starrt. Eine Charge überfälliger Rechnungserinnerungen versenden, ein Leaderboard über Nacht neu berechnen, abgelaufene Sessions bereinigen — nichts davon gehört in einen Request, der eigentlich in unter einer Sekunde zurückkommen soll. Das braucht seinen eigenen Zeitplan, seinen eigenen Trigger und seine eigene Fehlerbehandlung, getrennt vom Seitenaufruf oder API-Call, auf den ein Nutzer tatsächlich wartet.
Warum es zuerst kaputtgeht, wenn man es in einen Request-Handler stopft
Die verlockende Abkürzung ist, Hintergrundarbeit an den nächstbesten Request anzuflanschen. Ein „wöchentlicher Digest"-Job wird beim Laden der Dashboard-Seite ausgelöst, sodass der Digest nur verschickt wird, wenn zufällig jemand an dem Tag das Dashboard besucht. Eine Cleanup-Aufgabe läuft innerhalb eines Signup-Handlers, weil dort jemand daran gedacht hat, sie einzubauen.
Ich habe gesehen, wie dieses Muster zwei Arten von Fehlern verursacht. Entweder läuft der Request in ein Timeout, weil er jetzt fünf Minuten Reportgenerierung erledigen muss, bevor er antworten kann, oder der Job läuft still niemals, weil der „richtige" Request an dem Tag einfach nicht stattfand. Beides ist kein Bug, den man in einer Demo entdeckt. Beides zeigt sich zwei Wochen nach dem Launch, meist als Kundenanfrage, warum die Rechnungserinnerung nie ankam.
Das Anzeichen, dass Sie einen echten Hintergrundjob brauchen
Wenn bei der Beschreibung einer Aufgabe die Worte „jede Nacht", „jede Stunde" oder „irgendwann, nicht jetzt gleich" fallen, gehört sie nicht in einen Request/Response-Zyklus. Sie gehört auf einen Zeitplan oder in eine Queue.
Die drei Formen, in denen Hintergrundarbeit tatsächlich vorkommt
Die meisten geplanten oder asynchronen Aufgaben in einer echten App fallen in eine von drei Kategorien, und diese sind nicht austauschbar.
Geplante Jobs laufen nach der Uhr, ohne dass ein Nutzer beteiligt ist — nächtliche Abrechnungsläufe, wöchentliche Digest-E-Mails, eine 3-Uhr-morgens-Bereinigung abgelaufener Passwort-Reset-Tokens. Diese werden durch Zeit ausgelöst, nicht durch etwas, das ein Nutzer getan hat.
Queued Jobs werden durch ein Ereignis ausgelöst, sollten aber die Antwort darauf nicht blockieren. Ein Nutzer lädt ein Video hoch; die Upload-Antwort kommt sofort zurück, und ein separater Prozess kümmert sich im Hintergrund um das Transcoding. Der Nutzer sieht einen „wird verarbeitet"-Status und dann eine Benachrichtigung, wenn es fertig ist.
Wiederholbare Jobs sind die Untergruppe beider Kategorien, die aus Gründen außerhalb Ihrer Kontrolle scheitern können — ein E-Mail-Anbieter ist down, eine Drittanbieter-API drosselt Sie — und die Backoff und ein Wiederholungslimit brauchen statt eines einzelnen stillen Fehlers.
Diese zu vermischen ist der Punkt, an dem Teams sich die Finger verbrennen. Einen Queued Job wie einen geplanten zu behandeln bedeutet, dass er auf den nächsten Uhrentakt wartet, statt sofort zu laufen. Einen geplanten Job so zu behandeln, als könne er nicht scheitern, bedeutet, dass eine einzige schlechte Nacht den gesamten Abrechnungslauf lahmlegt — ohne Aufzeichnung darüber, was passiert ist.
Wo das in einer mit Greta.sh gebauten App seinen Platz hat
Da Greta.sh eine Next.js-App mit einer Prisma-gestützten Datenbank aufsetzt, hat geplante und Hintergrundarbeit ein offensichtliches Zuhause, statt separate Infrastruktur nachträglich anflanschen zu müssen. Ein geplanter Job ist eine Next.js-API-Route — sagen wir app/api/cron/send-digest/route.ts — die per Timer über die Cron-Konfiguration der Plattform ausgelöst wird, keine Seite, die irgendjemand besucht. Queued-Arbeit bekommt eine einfache Job-Tabelle in derselben Datenbank: eine Zeile pro Aufgabe, eine Status-Spalte und eine schlanke Route, die anstehende Zeilen verarbeitet. Kein separater Message-Broker, den man für ein Projekt aufsetzen muss, das ein paar tausend E-Mails pro Woche verschickt.
Dieser letzte Punkt ist wichtiger, als er klingt. Ein dedizierter Queue-System wie ein Managed Broker ist die richtige Wahl, sobald Sie zehntausende Jobs pro Stunde verarbeiten. Darunter ist eine Status-Spalte mit Polling-Route einfacher zu durchschauen, leichter zu debuggen und ein Service weniger, der unabhängig von Ihrer App ausfallen kann.
Ein einfacher Vergleich: selbst gebaut vs. von Greta.sh aufgesetzt
| Aspekt | Selbst von Grund auf gebaut | Von Greta.sh aufgesetzt |
|---|---|---|
| Scheduling-Infrastruktur | Separaten Cron-Service oder Serverless-Trigger einrichten | Cron-Konfiguration lebt neben der App, gleiches Deployment |
| Job-Status-Tracking | Individuelle Tabelle und Statuslogik pro Projekt | Prisma-Schema liefert von Tag eins an ein Job-Tabellen-Muster |
| Retry und Backoff | Pro Job geschrieben, unter Zeitdruck oft übersprungen | Standardmuster, konsistent über alle Job-Typen angewendet |
| Fehlersichtbarkeit | Logs über mehrere Services verstreut | Eine Datenbank, eine Stelle, um zu prüfen, „was ist letzte Nacht schiefgelaufen" |
| Späteres Hochskalieren | Migration auf ein Queue-System mitten im Projekt | Gleiche Next.js-Routes; Job-Tabelle gegen einen Broker tauschen, wenn das Volumen es verlangt |
Wie das end-to-end aussieht
Angenommen, Sie betreiben eine Abo-App und müssen jedes Konto herabstufen, dessen Testphase ohne hinterlegte Zahlungsmethode abgelaufen ist. Das ist ein geplanter Job: einmal am Tag nach abgelaufenen Testphasen suchen, deren Status umschalten, eine Hinweis-E-Mail senden. Das hat nichts mit dem Request eines einzelnen Nutzers zu tun — er muss laufen, egal ob sich an dem Tag jemand einloggt oder nicht.
Nehmen wir nun an, ein Nutzer exportiert einen großen Report aus derselben App. Der Export sollte die Seite nicht dreißig Sekunden lang blockieren, während er generiert wird. Der Request erzeugt eine Job-Zeile, antwortet sofort mit „wir schicken Ihnen eine E-Mail, wenn es fertig ist", und ein separater Prozess greift die Zeile auf, baut die Datei und aktualisiert den Status. Wenn die Reportgenerierung fehlschlägt, weil eine Drittanbieter-Datenquelle in ein Timeout gelaufen ist, versucht der Job es zweimal mit kurzer Verzögerung erneut, bevor er aufgibt und sich für einen Menschen zur Prüfung markiert.
Keines dieser beiden Szenarien ist für sich genommen kompliziert. Was Teams zum Verhängnis wird, ist das Überspringen der Retry-Logik in der Annahme, dass „das meist einfach funktioniert" — bis sie beim ersten schlechten Fünf-Minuten-Ausfall eines E-Mail-Anbieters eines Besseren belehrt werden.
FAQ
Brauche ich von Tag eins an eine Message-Queue wie Redis oder SQS? Fast nie. Eine Datenbanktabelle mit einer Status-Spalte bewältigt ein überraschend hohes Volumen — die meisten Apps wachsen nicht darüber hinaus, bevor sie Product-Market-Fit gefunden haben. Fügen Sie eine dedizierte Queue hinzu, wenn Sie so viele Jobs pro Minute verarbeiten, dass das Polling der Tabelle zum Flaschenhals wird — nicht vorher.
Wie oft kann ein geplanter Job tatsächlich laufen? Hängt von der Cron-Granularität der Plattform ab, aber minütliche Trigger sind bei Serverless-Cron üblich. Für alles Häufigere brauchen Sie in der Regel einen persistenten Worker-Prozess statt einer geplanten Funktion.
Was passiert, wenn sich ein geplanter Job mit sich selbst überschneidet — er läuft noch, wenn der nächste Trigger feuert? Das ist ein reales Fehlerszenario, kein hypothetisches. Die Lösung ist ein Lock: prüfen, ob der letzte Lauf beendet wurde, bevor ein neuer startet, oder ein Status-Flag am Job-Datensatz selbst verwenden.
Kann ich einen Hintergrundjob von einem Webhook statt von einem Zeitplan auslösen? Ja — das ist das Queued-Job-Muster. Ein Webhook kommt an, Sie schreiben eine Job-Zeile statt inline zu verarbeiten, und eine separate Route oder ein Worker kümmert sich kurz darauf darum. Siehe Webhooks und Drittanbieter-APIs verbinden für die eingehende Seite davon.
Fazit
Hintergrundjobs sind eine dieser Sachen, die in einer Demo nicht auftauchen — niemand klatscht für einen Cron-Job, der still um 3 Uhr morgens gelaufen ist —, aber sie machen den Unterschied zwischen einer App, die funktioniert, wenn jemand zuschaut, und einer, die tatsächlich unbeaufsichtigt ein Geschäft betreibt. Bekommen Sie Scheduling, Retries und Fehlersichtbarkeit richtig hin, und das meiste, was wie „Infrastrukturarbeit" aussah, entpuppt sich als eine Datenbanktabelle und eine Route.