---
term: 'Hintergrund-Jobs und Task-Scheduler'
seoTitle: 'Hintergrund-Jobs und Task-Scheduler: Queues, Worker, Retries'
headline: 'Was sind Hintergrund-Jobs und Task-Scheduler?'
slug: hintergrund-jobs
category: backend-compute
shortDefinition: 'Ein Hintergrund-Job ist eine Aufgabe außerhalb des Anfragezyklus – von der App eingereiht, von Workern ausgeführt, bei Fehlern wiederholt.'
relatedTerms:
  - scheduled-cloud-code-cron-jobs
  - cloud-code-serverless-functions
  - pub-sub-pattern
  - webhooks
contrastsWith:
  - scheduled-cloud-code-cron-jobs
aboutTerms:
  - 'Job Queue'
  - 'Worker'
  - 'Dead-Letter Queue'
  - 'Cron'
faq:
  - question: 'Was ist ein Hintergrund-Job?'
    answer: 'Eine Aufgabe, die Ihre Anwendung außerhalb des Anfrage-Antwort-Zyklus ausführt: Der Server reiht die Arbeit in eine Queue ein, antwortet dem Nutzer sofort, und ein separater Worker führt sie asynchron aus – mit Wiederholungsversuchen, falls sie scheitert. Alles Langsame, Wiederholbare oder für die Antwort Unnötige gehört dorthin.'
  - question: 'Warum die Arbeit nicht einfach im Request-Handler erledigen?'
    answer: 'Weil langsame Arbeit die Antwort blockiert, Serverkapazität bindet und in Gateway-Zeitüberschreitungen läuft – und wenn sie mitten in der Anfrage scheitert, bekommt der Nutzer einen Fehler, obwohl ein Teil bereits passiert ist. Das klassische Beispiel: die Willkommens-E-Mail während der Registrierung, wo ein langsamer Mailserver die Kontoerstellung in ein drehendes Rädchen verwandelt.'
  - question: 'Wie funktioniert eine Job-Queue?'
    answer: 'Sie ist eine dauerhafte Liste zwischen Produzenten und Workern: Die App legt einen Job ab – einen Typ plus einen kleinen Payload –, die Queue speichert ihn dauerhaft, und Worker holen ihn, führen ihn aus und bestätigen ihn. Unbestätigte Jobs kehren in die Queue zurück, und genau daher kommt die Zuverlässigkeit.'
  - question: 'Was ist der Unterschied zwischen einer Job-Queue und einer Message-Queue?'
    answer: 'Der Zweck. Eine Message-Queue transportiert Daten zwischen Diensten – die Zustellung ist das Ziel, und eine Nachricht kann an viele Konsumenten gehen. Eine Job-Queue führt Arbeit aus – sie legt Wiederholungsversuche, Planung, Prioritäten und Status obendrauf, und jeder Job geht an genau einen Worker.'
  - question: 'Was ist der Unterschied zwischen Cron-Jobs und Hintergrund-Jobs?'
    answer: 'Der Auslöser. Cron ist zeitgesteuert – "jede Nacht um 2 Uhr"; Hintergrund-Jobs sind ereignisgesteuert – "wenn ein Nutzer eine Datei hochlädt". Die Muster ergänzen sich: Ein verbreiteter Entwurf lässt cron den nächtlichen Batch einreihen, während Worker ihn mit der vollen Wiederholungssemantik ausführen.'
  - question: 'Wie funktionieren Wiederholungsversuche bei Jobs?'
    answer: 'Gescheiterte Jobs laufen automatisch erneut, mit exponentiellem Backoff – eine Sekunde, dann zwei, vier, acht – plus zufälligem Jitter, damit tausend Fehlschläge nicht alle im selben Moment wiederholen, begrenzt durch eine maximale Versuchszahl. Backoff überbrückt vorübergehende Störungen; die Obergrenze verhindert, dass dauerhafte Fehler ewig wiederholt werden.'
  - question: 'Warum müssen Hintergrund-Jobs idempotent sein?'
    answer: 'Weil Queues eine Ausführung mindestens einmal zusichern: Ein Worker kann abstürzen, nachdem er die Arbeit erledigt, aber bevor er sie bestätigt hat – und der Job läuft erneut. Zweimal laufen darf nicht zweimal abrechnen; Idempotenzschlüssel, Eindeutigkeits-Constraints und Upserts machen aus Duplikaten Leerläufe.'
  - question: 'Was ist eine Dead Letter Queue?'
    answer: 'Dorthin wandern Jobs, die ihre Wiederholungsversuche aufgebraucht haben – aufbewahrt zur Prüfung, zur Alarmierung und zum manuellen erneuten Abspielen, statt ewig zu wiederholen oder still zu verschwinden. Fehlerhaft aufgebaute Jobs, die nie gelingen können, sollten die Versuche überspringen und direkt dort landen.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'Sidekiq Best Practices'
    url: 'https://github.com/sidekiq/sidekiq/wiki/Best-Practices'
  - name: 'Celery — Distributed Task Queue'
    url: 'https://docs.celeryq.dev/en/stable/getting-started/introduction.html'
  - name: 'crontab(5) — Linux manual page'
    url: 'https://man7.org/linux/man-pages/man5/crontab.5.html'
  - name: 'Scaling Slack''s Job Queue — Slack Engineering'
    url: 'https://slack.engineering/scaling-slacks-job-queue/'
  - name: 'Job scheduler — Wikipedia'
    url: 'https://en.wikipedia.org/wiki/Job_scheduler'
cta:
  title: 'Jobs ohne Queue, die Sie betreiben müssen'
  text: 'Definieren Sie einen Cloud Job auf Back4app und führen Sie ihn bei Bedarf oder nach Zeitplan aus dem Dashboard aus – Status, Logs und Wiederholung inklusive, ohne Broker, Worker-Flotte oder Queue-Infrastruktur im Betrieb.'
  linkText: 'Kostenlos starten'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-09-25'
translationKey: background-jobs-task-schedulers
---

**Ein Hintergrund-Job ist eine Aufgabe außerhalb des Anfragezyklus – von der App eingereiht, von Workern ausgeführt, bei Fehlern wiederholt.** Die Trennlinie ist die Zeit: Eine Antwort soll sich sofort anfühlen (ein paar hundert Millisekunden) und *muss* die Gateway-Zeitüberschreitung schlagen (typischerweise etwa 30 Sekunden), während echte Arbeit – E-Mails über SMTP, Bildverarbeitung, Berichtserstellung, APIs von Drittanbietern – Sekunden bis Minuten dauert und Wiederholungsversuche verdient. Alles auf der falschen Seite dieser Linie wird eingereiht, bestätigt und anderswo erledigt; in großem Maßstab ist das Kerninfrastruktur und keine Klempnerei – ein großer Messaging-Anbieter verarbeitet täglich über eine Milliarde Jobs durch genau diese Maschinerie.

## Das Wichtigste im Überblick

| Frage | Antwort |
| --- | --- |
| Die Architektur | Produzent reiht ein → Queue speichert dauerhaft → Worker führt aus und bestätigt |
| Die Trennlinie | Antwortbudget etwa 300 ms; alles Langsame oder Wiederholbare wird ein Job |
| Die drei Zeitmodi | Sofort · verzögert ("in 24 h") · wiederkehrend (cron) |
| Der Zuverlässigkeitsvertrag | Mindestens einmal + idempotente Jobs + Backoff mit Jitter + Dead Letters |
| Das stille Scheitern | Nichts meldet einen Fehler, wenn ein geplanter Job ausbleibt – überwachen Sie die Abwesenheit |

## Das Anti-Muster, das alles lehrt

```js
// ✗ Die Registrierung, die sich einem Mailserver ausliefert
app.post('/signup', async (req, res) => {
  const user = await createUser(req.body);
  await sendWelcomeEmail(user);        // SMTP langsam? Der Nutzer starrt auf den Spinner.
  res.json(user);                      // SMTP tot? Registrierung liefert 500 – aber das
});                                    // Konto EXISTIERT. Schlimmer geht es nicht.

// ✔ Einreihen und antworten
app.post('/signup', async (req, res) => {
  const user = await createUser(req.body);
  await jobs.enqueue('welcomeEmail', { userId: user.id }); // Millisekunden
  res.json(user);                      // Die E-Mail geht raus, wiederholt sich
});                                    // und gelingt im eigenen Takt – unsichtbar
```

Dasselbe Prinzip von beiden Seiten eines echten Backends – ein Job über den Daten und ein Client, der einreiht statt zu warten:

**JavaScript:**

```javascript
// JavaScript — Cloud Code (cloud/main.js)
// A background job: heavy work outside the request cycle
Parse.Cloud.job('sendWeeklyDigest', async (request) => {
  const query = new Parse.Query(Parse.User).equalTo('digestOptIn', true);
  await query.eachBatch(async (users) => {
    for (const user of users) await sendDigest(user); // per-record, resumable
  }, { useMasterKey: true });
  request.message('Digest run complete'); // status visible in the dashboard
});
// Run on demand or on a schedule from the dashboard — no queue to operate
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// The client's rule: never wait on heavy work — enqueue and move on
final export = ParseObject('ExportRequest')
  ..set('user', currentUser)
  ..set('status', 'queued'); // an afterSave trigger starts the work
await export.save(); // returns in milliseconds

// Watch the job's progress like any other data:
final sub = await LiveQuery().client.subscribe(
    QueryBuilder<ParseObject>(ParseObject('ExportRequest'))
      ..whereEqualTo('objectId', export.objectId));
sub.on(LiveQueryEvent.update, (job) {
  if (job.get<String>('status') == 'done') openReport(job.get('fileUrl'));
});
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// The client's rule: never wait on heavy work — enqueue and move on
var export = ExportRequest()
export.status = "queued" // an afterSave trigger starts the work
let saved = try await export.save() // returns in milliseconds

// Watch the job's progress like any other data:
let sub = try await ExportRequest.query("objectId" == saved.id).subscribe()
sub.handleEvent { _, event in
    if case .updated(let job) = event, job.status == "done" {
        openReport(job.fileUrl)
    }
}
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// The client's rule: never wait on heavy work — enqueue and move on
val export = ParseObject("ExportRequest")
export.put("user", ParseUser.getCurrentUser())
export.put("status", "queued") // an afterSave trigger starts the work
export.save() // returns in milliseconds

// Watch the job's progress like any other data:
val q = ParseQuery.getQuery<ParseObject>("ExportRequest")
q.whereEqualTo("objectId", export.objectId)
val sub = ParseLiveQueryClient.Factory.getClient().subscribe(q)
sub.handleEvent(SubscriptionHandling.Event.UPDATE) { _, job ->
    if (job.getString("status") == "done") openReport(job.getString("fileUrl"))
}
```

## Produzent, Queue, Worker

```mermaid
flowchart LR
  accTitle: Architektur aus Produzent, Queue und Worker mit Wiederholungsversuchen und Dead Letters
  accDescr: Die Anwendung reiht Jobs in eine dauerhafte Queue ein und antwortet Nutzern sofort. Worker holen Jobs, führen sie aus und bestätigen sie bei Erfolg. Gescheiterte Jobs werden mit exponentiellem Backoff erneut eingereiht, und Jobs, die ihre Wiederholungsversuche aufbrauchen, wandern in eine Dead Letter Queue zur Prüfung und zum erneuten Abspielen.
  A["App (Produzent)<br/>einreihen + schnell antworten"] --> Q[("Queue<br/>dauerhaft, halbwegs geordnet")]
  S["Scheduler<br/>cron: pünktlich neu einreihen"] --> Q
  Q --> W["Worker<br/>holen · ausführen · bestätigen"]
  W -->|"Erfolg"| OK["Fertig"]
  W -.->|"Fehlschlag"| B["Backoff + Jitter<br/>warten, dann neu einreihen"] -.-> Q
  B -.->|"Versuche aufgebraucht"| DL["Dead Letter Queue<br/>prüfen · alarmieren · abspielen"]
```

Drei Rollen, ein Vertrag. Der **Produzent** – meist ein Request-Handler – erzeugt einen Job: einen Typnamen und einen kleinen Payload. Die **Queue** speichert ihn dauerhaft; die Dauerhaftigkeit ist der ganze Punkt, denn Arbeit, die nur im Speicher eines sterbenden Prozesses existiert, stirbt mit ihm. **Worker** holen, führen aus und *bestätigen* (ack); ein Job ist erst weg, wenn er bestätigt ist – so überlebt der Job eines abgestürzten Workers und läuft erneut. Das Vokabular, das mitreist: enqueue/dequeue, Acks, Visibility Timeouts, und die Unterscheidung, auf die man achten sollte – eine *Message*-Queue transportiert Daten zwischen Diensten (und kann an [viele Abonnenten](/glossary/pub-sub-pattern/) verteilen); eine *Job*-Queue führt Arbeit aus, genau einmal pro Job und Worker, mit eingebauten Wiederholungsversuchen und Status.

## Die drei Zeitmodi – und eine kurze Cron-Einführung

Jedes Job-System setzt dieselben drei Zeitmodi um: **sofort** (jetzt einreihen, laufen lassen, sobald ein Worker frei wird), **verzögert** (jetzt einreihen, zu einem späteren Zeitpunkt fällig – Erinnerungen, Ablauf von Testphasen und der Wiederholungsmechanismus selbst) und **wiederkehrend** (ein Scheduler reiht nach Kalender neu ein). Wiederkehrende Zeitpläne schreibt man fast immer in den fünf Feldern von [cron](https://man7.org/linux/man-pages/man5/crontab.5.html):

```text
┌ Minute (0-59)  ┌ Stunde (0-23)  ┌ Tag des Monats  ┌ Monat  ┌ Wochentag
0 2 * * *      → täglich um 02:00
*/15 * * * *   → alle 15 Minuten
0 9 * * 1      → montags um 09:00

Zwei Minen für den Scheduler: Sommerzeitwechsel (02:30 verschwindet oder
tritt zweimal auf – planen Sie in UTC) und Überlappung (ein Lauf, der sein
Intervall überdauert, braucht eine Sperre, sonst verarbeiten zwei Kopien
dieselben Daten).
```

## Job-Queues vs. Message-Queues vs. Scheduler

| | Job-Queue | Message-Queue | Scheduler |
| --- | --- | --- | --- |
| Einheit | Ein auszuführender Job | Eine zuzustellende Nachricht | Ein Auslösezeitpunkt |
| Konsumenten | Genau ein Worker | Einer oder [viele Abonnenten](/glossary/pub-sub-pattern/) | Die Jobs, die er einreiht |
| Eingebaut | Wiederholungen, Status, Prioritäten, Verzögerung | Dauerhaftigkeit, Routing, Fan-out | Kalender, Wiederholung |
| Open-Source-Namen | Sidekiq, Celery, BullMQ | RabbitMQ, Kafka, Redis | cron, Quartz |
| Fügt sich ein als | Führt aus, was Ereignisse verlangen | Transportiert zwischen Systemen | Speist die Queue pünktlich |

Die Komposition beantwortet die meisten "Welches davon?"-Debatten: Scheduler entscheiden *wann*, Queues halten *was*, Worker erledigen das *Tun* – und ein nächtlicher Batch ist cron, das Jobs einreiht, die Worker mit der vollen Wiederholungssemantik ausführen.

## Der Zuverlässigkeitsvertrag

Die Teile werden meist getrennt gelehrt; sie sind ein einziger Vertrag. **Die Queue sichert mindestens einmal zu** – ein Worker, der nach der Arbeit, aber vor der Bestätigung abstürzt, bedeutet, dass der Job erneut läuft; das ist unvermeidlich, nicht schlampig. **Sie sichern im Gegenzug Idempotenz zu**: nach Job-ID deduplizieren, mit Eindeutigkeits-Constraints absichern, mit Upserts schreiben – damit der zweite Lauf ein Leerlauf ist statt einer zweiten Rechnung. **Wiederholungsversuche mit exponentiellem Backoff und Jitter** überbrücken vorübergehende Störungen – 1 s, 2 s, 4 s, mit Zufallsanteil, damit tausend gemeinsam gescheiterte Jobs nicht gemeinsam wiederholen, eine Höflichkeit, die [ratenbegrenzte Drittanbieter](/glossary/de/api-rate-limiting/) erzwingen, wenn Sie sie nicht von sich aus erweisen. **Die Dead Letter Queue fängt den Rest ab**: Nach der Versuchsobergrenze parken Jobs dort, wo Menschen sie prüfen, reparieren und erneut abspielen können – und dauerhaft fehlerhafte Jobs sollten das Wiederholungstheater ganz überspringen und direkt dorthin gehen.

## Jobs gut entwerfen

Die Regeln, auf die sich die Queue-Frameworks einigen, zusammengetragen: **IDs übergeben, keine Objekte** – ein Payload mit `userId: "u-8fk2"` holt zur Laufzeit frischen Zustand, während ein serialisiertes Nutzerobjekt schon im Moment des Einreihens veraltet ist; **Payloads klein halten** und JSON-einfach, niemals Secrets; **ein Job pro Datensatz** – ein Job je Nutzer wiederholt bei einem Fehler einen Nutzer, ein Mega-Job wiederholt alle; **lange Arbeit fortsetzbar machen** – in Blöcke zerlegen, Fortschritt festhalten und bei Shutdown-Signalen mitten im Block sauber aussteigen; und **von Nebenläufigkeit ausgehen** – irgendwann verarbeiten zwei Worker benachbarte Jobs auf derselben Zeile, und das ist eine Frage der Sperren, die Sie beim Entwurf oder im Störfall beantworten.

## Die Queue im Blick behalten

Scheitern im Hintergrund ist still – kein Nutzer sieht eine Fehlerseite, wenn der Digest-Job stirbt. Die vier Messgrößen, die die Fehlerseite ersetzen: **Queue-Tiefe** (ein wachsender Rückstand heißt, die Worker verlieren), **Job-Alter** gemessen vom Einreihen bis zum Abschluss – ein Job, der nach 40 Minuten Wartezeit in 200 ms verarbeitet wird, ist für den Nutzer ein 40-Minuten-Job; **Fehler- und Dead-Letter-Raten** mit Alarmen auf der Dead Letter Queue, denn geparkte Jobs, die jemand vergessen hat, sind Daten, die still nicht verarbeitet werden; und **ausgebliebene Läufe** bei geplanter Arbeit – der besonders heimtückische Fall, denn ein Zeitplan, der nie gefeuert hat, erzeugte keinen Fehler, keine Logzeile und überhaupt keinen Job. Alarmieren Sie auf die Abwesenheit.

## Typische Anwendungsfälle

- **E-Mail und Benachrichtigungen** – die klassische Verschiebung: bei der Registrierung einreihen, mit Wiederholungen zustellen.
- **Medienverarbeitung** – Skalieren, Transkodieren, Vorschaubilder: Minuten an CPU-Zeit, auf die keine Anfrage warten sollte.
- **Berichte und Exporte** – im Hintergrund erzeugen, benachrichtigen, sobald die Datei bereit ist.
- **Synchronisation mit Drittanbietern** – CRM-Abgleiche und [Webhook](/glossary/de/webhooks/)-Zustellungen, mit Backoff gegen wackelige Gegenstellen.
- **Bereinigung und Wartung** – TTL-Durchläufe, Entfernen von Waisen, Digest-Erstellung im nächtlichen Cron-Job.

## Welches Muster brauchen Sie? Entscheidungsmatrix

| Die Arbeit sieht so aus | Greifen Sie zu |
| --- | --- |
| Von Nutzeraktionen ausgelöst, schwankendes Volumen | Job-Queue + Worker |
| Fester Kalender, begrenzt, vorhersehbar | Geplanter Job (cron) |
| Nächtlicher Batch über viele Datensätze | Cron reiht ein; Worker führen pro Datensatz aus |
| Dienste, die einander etwas mitteilen | [Message-Queue / Pub-Sub](/glossary/pub-sub-pattern/) |
| Heute langsame Arbeit im Request-Handler | Das Refactoring von oben – einreihen und antworten |
| Muss Abstürze überstehen und sicher wiederholen | Alles davon – plus der Zuverlässigkeitsvertrag |

## Grenzen und Trade-offs

- **Letztendlich, nicht sofort.** Eingereihte Arbeit passiert *später* – Oberflächen brauchen Wartezustände, und "später" braucht eine Obergrenze, die jemand bewusst gewählt hat.
- **Zustand wandert aus dem Takt.** Ergebnisse kommen über Statusfelder, Callbacks oder Benachrichtigungen – die Einfachheit von Anfrage und Antwort ist verbraucht, planen Sie die Verkabelung ein.
- **Infrastruktur ist real.** Broker, Worker und Scheduler sind Dienste mit eigenen Fehlermodi – oder das Problem einer Plattform, was das Argument für verwaltete Jobs ist.
- **Duplikate sind irgendwann garantiert.** "Mindestens einmal" ist der Vertrag; jeder nicht idempotente Job ist ein Störfall mit Zeitzünder.
- **Queues verbergen Überlast elegant – zu elegant.** Ein wachsender Rückstand wirkt ruhig, bis das Job-Alter explodiert; Alarme auf Tiefe und Alter sind der Ehrlichkeitsmechanismus.

## Hintergrund-Jobs mit Back4app

Back4app ist eine Open-Source-Plattform für Backend as a Service (BaaS), die eine verwaltete Datenbank, automatisch generierte REST- und GraphQL-APIs, Authentifizierung, Dateispeicher und Serverless-Funktionen mit Cloud Code kombiniert. Jobs sind hier [Cloud Code](/glossary/de/cloud-code-serverless-funktionen/) mit einem Zeitplan: Definieren Sie `Parse.Cloud.job` – die Code-Tabs zeigen einen Digest-Job, der mit `eachBatch` über Nutzer hinweg in Blöcken arbeitet, pro Datensatz und fortsetzbar – und führen Sie ihn bei Bedarf oder in einer Wiederholung im Cron-Stil aus dem Dashboard aus, mit Status und Logs im Jobs-Panel; kein Broker bereitzustellen, keine Worker-Flotte zu skalieren, kein Queue-Dienst am Leben zu halten. Die ereignisgesteuerte Hälfte setzt sich aus denselben Bausteinen zusammen: Ein Request-Handler schreibt eine Zeile mit `status: "queued"`, ein `afterSave`-Trigger startet die Arbeit, und Clients verfolgen den Fortschritt über [Live Queries](/glossary/de/live-queries-echtzeit/), statt zu pollen – das Produzent-Worker-Muster als Daten ausgedrückt, mit dem Zuverlässigkeitsvertrag (IDs im Payload, idempotente Handler, Status, auf den Sie alarmieren können) als Ihrer Entwurfsdisziplin statt als Ihrer Infrastruktur.
