HiAPI
Blog

Tutorial

hiapi /v1/tasks hängende oder in Timeout laufende Tasks: Diagnoseablauf und Retry-Strategie

Oct 13, 2026
hiapi /v1/tasks hängende oder in Timeout laufende Tasks: Diagnoseablauf und Retry-Strategie

Du hast einen Task an POST https://api.hiapi.ai/v1/tasks übermittelt und eine taskId erhalten, doch wenn du mit GET /v1/tasks/{taskId} nachfragst, steht data.status mehrere Minuten lang noch auf queued oder handling – es sieht „hängend“ aus; oder deine Polling-Schleife hat ihr selbst gesetztes Limit erreicht, ohne einen Endzustand zu sehen, und meldet daher einen Timeout. Überstürze nicht gleich einen erneuten Submit: Die Tasks von hiapi sind asynchron, „noch nicht beendet“ und „bereits fehlgeschlagen“ sind zwei verschiedene Dinge. Erst sauber diagnostizieren, dann handeln – sonst wird es beim Reparieren nur schlimmer.

Wenn du siehst, dass data.status bereits fail ist, error.code gleich TASK_TIMEOUT ist, oder wenn Browser/Proxy ein wörtliches HTTP 504 werfen – das ist eine andere Problemklasse (der Task ist tatsächlich fehlgeschlagen, oder der Timeout tritt auf der Netzwerkebene zwischen dir und hiapi auf). Siehe dazu HiAPI Task-Timeout und 504-Fehlerbehebung. Dieser Artikel behandelt nur das „Hängen“-Szenario, bei dem ein Task lange nicht in den Endzustand kommt.

Symptome

Ein „hängender“ Task sieht bei der Abfrage ungefähr so aus (HTTP 200, aber der Task ist noch in einem Nicht-Endzustand):

{
  "data": {
    "taskId": "…",
    "status": "queued",
    "output": null,
    "error": null
  }
}

Wesentliche Merkmale: data.status ist eines von queued (in Warteschlange) / handling (in Bearbeitung) / archiving (wird archiviert), data.error ist null, und data.output hat noch keinen Inhalt. Das bedeutet, der Task ist gesund, nur noch nicht fertig.

hiapi-Tasks haben nur zwei Endzustände: data.status ist success oder fail. Solange es nicht diese beiden sind, ist der Task nicht beendet – „Hängen“ passiert fast immer in diesem Nicht-Endzustand.

Zwei leicht verwechselbare „Schein-Hänger“:

  • Die Abfrage gibt direkt 404 zurück:

    {"code": 404, "data": null, "message": "task not found"}
    

    Das ist kein Hängen, sondern die taskId ist falsch geschrieben, der Task wurde gar nicht erfolgreich erstellt, oder der Task-Datensatz ist abgelaufen – prüfe die data.taskId, die du beim Submit erhalten hast.

  • Beim Submit wird synchron abgelehnt (du hast gar keine taskId erhalten), z. B. wegen eines falschen model:

    {"code": 400, "data": null, "error_code": "MODEL_UNAVAILABLE", "message": "model not available via /v1/tasks"}
    

    Das ist ein Problem der Anfrage selbst, kein hängender Task – korrigieren und erneut senden.

Häufige Ursachen (nach Trefferwahrscheinlichkeit sortiert)

1. Rückstau in der Warteschlange (am häufigsten)

Wenn ein Modell (Bildmodell, Videomodell oder ein beliebiges rechenintensives Modell) gerade stark aufgerufen wird, wartet dein Task in der Warteschlange dieses Modells darauf, von einem Worker aufgenommen zu werden.

  • Signal: data.status ist queued, data.error ist null, und seit dem Submit ist nicht viel Zeit vergangen.
  • Behebung: Verlangsame das Polling – alle 5–10 Sekunden abzufragen reicht, nicht im 100-ms-Leerlauf drehen. Die meisten Tasks werden innerhalb von ein bis zwei Minuten aufgenommen.

2. Schwere Modelle brauchen ohnehin lange

Der Task wurde bereits aufgenommen (handling/archiving), aber dieses Modell braucht für einen Lauf grundsätzlich lange – lange Videos, hohe Auflösung und viele Referenzbilder verlängern die Laufzeit deutlich.

  • Signal: data.status steht auf handling oder archiving, seit mehreren Minuten, aber ohne Fehler.
  • Behebung: Gib schweren Tasks ein großzügigeres Polling-Limit (mit genug Reserve je nach Modellfähigkeit). Lange Laufzeit ≠ Fehler – brich nicht selbst ab, wenn das Ergebnis fast da ist.

3. Falsche Polling-Strategie (am leichtesten als „Hängen“ fehlinterpretiert)

Viele „Hänger“ sind tatsächlich Client-Probleme: Das Polling-Intervall ist zu kurz und man verheddert sich, es gibt kein Limit, oder das Limit ist zu kurz und man gibt zu früh auf.

  • Signal: Server-seitig schreitet data.status normal voran, aber deine Schleife wirft vorzeitig einen Timeout, oder du liest data.status gar nicht aus.
  • Behebung: Verwende ein festes Intervall (empfohlen: 5 Sekunden) + ein vernünftiges Limit (normale Tasks etwa 10 Minuten, schwere Tasks länger). Der Timeout sollte von deiner Schleife bestimmt werden, nicht von einem serverseitigen timeout-Status – den gibt es bei hiapi nicht.

4. Callback-Endpunkt nicht erreichbar

Wenn du beim Submit einen Callback (callback) mitgeschickt hast, kann der Task selbst bereits success sein – nur kommt das Ergebnis nicht bei dir an, und es sieht deshalb „still“ aus.

  • Signal: Eine aktive Abfrage zeigt data.status bereits als success, data.output hat Inhalt, aber dein Callback-Endpunkt hat nichts empfangen.
  • Behebung: Die Callback-Adresse muss öffentlich erreichbar sein, POST annehmen können und innerhalb von etwa 10 Sekunden 2xx zurückgeben; andernfalls wechsle zu Polling. Details siehe Warum hiapi-Task-Callbacks nicht ausgelöst werden.

Behebungsschritte

  1. Erst den Status abfragen, nicht aus dem Bauch heraus neu submitten: GET /v1/tasks/{taskId}, lies data.status und data.error.
  2. Je nach Status verzweigen:
    • queued / handling / archiving → läuft noch, in 5–10 Sekunden erneut prüfen (Ursache 1 / 2).
    • success → Task erfolgreich, hole das Ergebnis aus data.output; wenn du auf einen Callback wartest und keinen erhältst → Ursache 4.
    • fail → lies data.error.code und data.error.message; bei TASK_TIMEOUT → siehe Timeout- und 504-Leitfaden.
    • 404 task not found → taskId ist falsch oder der Task wurde nicht erfolgreich erstellt; prüfe die data.taskId aus der Submit-Antwort.
  3. output ist zeitlich begrenzt: Die Download-URL in data.output hat ein expireAt (ca. 7 Tage). Speichere das Ergebnis so schnell wie möglich lokal / kopiere es, speichere keine Hotlinks langfristig.
  4. Stelle sicher, dass es kein Auth-/Request-Problem ist: Führe zuerst das folgende minimale Verifikationsbeispiel aus, um Probleme mit Key und model id auszuschließen.
  5. Wenn wirklich ein Retry nötig ist, mit Backoff: Siehe die Retry-Strategie im nächsten Abschnitt – nicht in einer engen Schleife denselben Body wiederholt submitten.

Minimales Verifikationsbeispiel

Bestätige mit einer minimalen Anfrage, dass Key und Task-API selbst funktionieren. Verwende für model die nackte id (z. B. gpt-image-2):

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2",
    "input": { "prompt": "a single red apple on a white background, studio lighting" }
  }'

Bei erfolgreichem Submit erhältst du eine Antwort wie {"data":{"taskId":"…","status":"queued"}}. Nimm die taskId und poll:

curl -s "https://api.hiapi.ai/v1/tasks/<taskId>" \
  -H "Authorization: Bearer $HIAPI_API_KEY"
  • Wenn 401 zurückkommt und der Body {"error":{"code":"permission_denied","type":"hiapi_error","request_id":"…"}} lautet – liegt das Problem am Key, nicht am Task. Siehe zuerst Fehlerbehebung bei ungültigem API Key.
  • Wenn der Submit mit 400 + "error_code":"MODEL_UNAVAILABLE" abgelehnt wird – liegt das Problem an der model id. Übergib die nackte id und vergleiche mit hiapi „Modell nicht verfügbar“-Fehler.

Retry-Strategie, die es nicht schlimmer macht

  1. Exponentielles Backoff: Empfohlen 5s → 15s → 45s.
  2. Maximal 3 Versuche: Beim dritten Fehlschlag eskaliere (Modell wechseln, Konfiguration reduzieren oder Ticket eröffnen), nicht endlos wiederholen.
  3. Jeder Retry ist ein neuer Task: Ein POST /v1/tasks erzeugt eine neue taskId und kann neue Abrechnung verursachen. hiapi bietet kein zugesichertes „idempotentes Wiederholen“ – erwarte nicht, dass ein erneuter Submit desselben Body den alten Task wiederverwendet.
  4. Bei 429 verlangsamst du die Submit-Rate, nicht die Poll-Rate: Siehe So behebst du den hiapi-Rate-Limit-Fehler (429).

Ein solides Python-Beispiel für Polling + Backoff:

import time, os, requests

BASE = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"}

def submit_and_wait(body, poll_interval=5, max_wait=600):
    r = requests.post(BASE, json=body, headers=HEADERS, timeout=30)
    r.raise_for_status()
    task_id = r.json()["data"]["taskId"]

    deadline = time.time() + max_wait
    while time.time() < deadline:
        time.sleep(poll_interval)
        data = requests.get(f"{BASE}/{task_id}", headers=HEADERS, timeout=30).json()
        status = (data.get("data") or {}).get("status")
        if status == "success":
            return data["data"]["output"]
        if status == "fail":
            raise RuntimeError(data["data"].get("error"))
        # queued / handling / archiving → weiter warten
    raise TimeoutError(f"task {task_id} hat innerhalb von {max_wait}s keinen Endzustand erreicht")

Beachte: Als Endzustand gelten nur success und fail; bei allen anderen Status (queued / handling / archiving) wird weiter gewartet, der Timeout wird durch dein max_wait bestimmt.

Wann eskaliert werden sollte

  • Drei Retries mit Backoff, jedes Mal derselbe data.error.code → kein kurzzeitiges Flackern, ändere die Eingabe oder wechsle das Modell.
  • Der Task bleibt lange auf queued ohne jeden Fortschritt → schau im hiapi Dashboard nach Plattformhinweisen und eröffne mit request_id ein Ticket.
  • data.status ist bereits success, aber der Callback kommt einfach nicht → verlasse dich bei diesem Endpunkt nicht mehr auf Callbacks, wechsle zu Polling.

Verwandte interne Links

FAQ

F: Ab wann gilt es als „Timeout“? Gibt es eine einheitliche Timeout-Dauer? A: Es gibt keine einheitliche Zahl; sie hängt vom Modell ab – schwere Tasks (lange Videos, hohe Auflösung) brauchen länger. Zudem gibt es bei hiapi keinen serverseitigen timeout-Status – der sogenannte Timeout ist meistens das Erreichen deines eigenen Limits in der Polling-Schleife. Ein tatsächlich serverseitig per Timeout fehlgeschlagener Task hat data.status:"fail" + error.code:"TASK_TIMEOUT"; für diesen Fall siehe Timeout- und 504-Leitfaden.

F: Der Task ist seit 30 Sekunden queued – sollte ich abbrechen und neu versuchen? A: Nein. 30 Sekunden liegen für jedes nicht-triviale Modell im normalen Bereich; warte mindestens zwei Minuten, bevor du an einen Retry denkst.

F: Kann man einen laufenden Task abbrechen? A: In der Regel nicht; selbst wenn ein Abbruch möglich wäre, sind Warteschlangen- / Rechenressourcen meist schon belegt. Es ist günstiger, den Task fertig laufen zu lassen und das Ergebnis abzufragen.

F: Dieselbe Anfrage lief gestern, heute hängt sie? A: In den allermeisten Fällen ist es ein Rückstau in der Warteschlange auf Modellebene (Ursache 1). Wechsle auf ein Modell mit ähnlichen Fähigkeiten oder warte 5–10 Minuten, bis sich die Warteschlange leert, und versuche es dann erneut.

F: Jeder Task läuft in einen Timeout – ist das ein Problem meines Kontos? A: Schau zuerst im hiapi Dashboard nach kontoweiten Hinweisen und prüfe, ob du ratenbegrenzt wirst (siehe 429-Leitfaden). Wenn alles normal ist und nur ein bestimmtes Modell fehlschlägt, liegt es wahrscheinlich an dessen Warteschlange oder Backend, nicht an deinem Konto.

F: Wird ein hängender / in Timeout gelaufener Task beim Retry doppelt abgerechnet? A: Jedes POST /v1/tasks ist ein neuer abzurechnender Task. Fehlgeschlagene Tasks ohne Ergebnis werden in der Regel nicht für die Ausgabe berechnet, aber Warteschlangen- / Rechenressourcen können bereits belegt sein. Wenn dir Kosten wichtig sind, prüfe es nachträglich auf der Nutzungsseite.

Ähnliche Artikel

Alle Artikel ansehen →

Starte mit persistenten KI-Artefakten

Hol dir deinen API-Key und rufe Bild-, Video- und Audiomodelle über eine einzige task-basierte API auf.

API-Dokumentation lesen