Zum Hauptinhalt springen

createTask – und dann? Polling oder Webhooks für asynchrone Generierungsaufgaben

Modelle liefern eine taskId. Wählen Sie Polling oder Webhooks und setzen Sie Aufgaben nach einem Timeout fort, ohne doppelt zu zahlen.

Autor
SpicyAPI Engineering
Erschienen
Lesedauer
7 Min. Lesezeit
Aktualisiert
Ein gewundener Pfad mit kreisförmigen Kontrollpunkten neben einem direkten goldenen Weg zu einer leuchtenden Kugel.

Sie haben createTask aufgerufen und statt eines Bildes eine taskId erhalten. Nun brauchen Sie das Ergebnis, ohne minutenlang eine Verbindung offen zu halten, nach einer Zeitüberschreitung doppelt zu zahlen oder die Aufgabe bei einem Neustart Ihres Prozesses zu verlieren.

Die Kurzfassung:

  • Schnelle Bildmodelle in einem Skript: Ergänzen Sie ?wait=30 beim Aufruf von createTask; oft entfällt damit das Polling vollständig.
  • Skripte, lokale Entwicklung, kein öffentlicher Server: Fragen Sie den Aufgabenstatus mit einer begrenzten Schleife wie im folgenden Beispiel ab.
  • Alles, worauf Nutzer warten, Video oder größere Mengen: Nutzen Sie callBackUrl, prüfen Sie die Signatur, bestätigen Sie den Empfang zügig und verarbeiten Sie Ereignisse über eine Warteschlange.
  • Produktion: Kombinieren Sie beides. Der Callback ist der schnelle Weg; eine regelmäßige Statusprüfung fängt Callbacks auf, die nie eintreffen.

In der direkten API hält ?wait=<seconds> (bis zu 60) den Aufruf von createTask offen, bis die Aufgabe endet. Das eignet sich für Bildmodelle, die in Sekunden fertig werden, aber nicht für Video. callBackUrl (mit großem B) ist die öffentliche HTTPS-Adresse, die das Ergebnis empfängt. recordInfo ist der Statusaufruf, den get_task im SDK kapselt. Die Aufgabenreferenz beschreibt alle drei.

Zuerst im Playground ausprobieren

Öffnen Sie den seedream-5-0-pro Playground. Geben Sie einen kurzen Prompt ein, stellen Sie Resolution auf 1k, drücken Sie Run model und lesen Sie das Ergebnis unter Output; History zeigt frühere Durchläufe. Die sichtbare Wartezeit automatisieren Polling und Webhooks für Ihre Anwendung; sie erzeugen kein zweites Bild.

Den Weg zum Ergebnis wählen

Ihre AnwendungBeginnen Sie mitWarum
Lokales Skript oder gelegentliche StapelverarbeitungPolling über das SDKKein öffentlicher Empfänger muss bereitgestellt werden
Interaktive Bild- oder VideoanwendungVerifizierter WebhookAuf den Abschluss reagieren, ohne für jede Aufgabe einen wartenden Prozess vorzuhalten
ProduktionsdienstWebhook plus regelmäßiger AbgleichEin verpasster Callback lässt eine angenommene Aufgabe nicht ohne weitere Betreuung zurück

Wählen Sie Polling, wenn die Anzahl der Aufgaben klein ist oder Ihr Rechner keine öffentlichen HTTPS-Aufrufe empfangen kann. Wählen Sie Webhooks, wenn Nutzer auf eine interaktive Anwendung warten oder lange Videoaufgaben Ihre Worker binden würden.

Bei Aufgaben mit Bildeingabe führt der Upload-Ablauf des SDK /files/{fileId}/commit aus und liefert eine spicy://-URI zurück; siehe Mediendokumentation.

Eine Aufgabe mit dem SDK ausführen

Installieren Sie spicyapi, setzen Sie SPICY_API_KEY und führen Sie das Beispiel aus. Bewahren Sie map-image.json auf, um dieselbe Aufgabe nach einer Unterbrechung fortzusetzen. Für ein bewusst anderes Bild verwenden Sie einen neuen Namen für den Durchlauf. Das Python SDK stellt die API-Methoden bereit; die Aufgabenreferenz erklärt den vollständigen Lebenszyklus.

python
import json
import os
import time
import uuid
from pathlib import Path
from spicyapi import SpicyClient, output_assets

client = SpicyClient()

def run(model, inputs, name):
    path = Path(name + ".json")
    request = {"model": model, "input": inputs}
    saved = json.loads(path.read_text()) if path.exists() else {"request": request, "key": str(uuid.uuid4())}
    if saved["request"] != request:
        raise ValueError("Changed input needs a new run name; preserve the old attempt.")
    def save():
        temporary = path.with_suffix(".tmp")
        temporary.write_text(json.dumps(saved))
        temporary.chmod(0o600)
        temporary.replace(path)
    if not saved.get("taskId"):
        if time.time() - saved.get("sentAt", time.time()) >= 23 * 3600:
            raise RuntimeError("Reconcile the saved attempt before submitting again.")
        if "quote" not in saved:
            saved["quote"] = client.quote_task(model=model, input_data=inputs)
            if input(f"Maximum ${saved['quote']['maxCharge']}. Create? [y/N] ") != "y":
                raise SystemExit("Stopped without creating this task.")
        saved.setdefault("sentAt", time.time())
        save()
        quote = saved["quote"]
        task = client.create_task(model=model, input_data=inputs,
            idempotency_key=saved["key"], quote_id=quote["quoteId"], expected_cost=quote["estimatedCost"])
        saved["taskId"] = task["taskId"]
        save()
    print("Task:", saved["taskId"])
    for _ in range(360):
        task = client.get_task(saved["taskId"])
        if task["state"] not in {"queued", "running"} and task["state"] != "succeeded":
            raise RuntimeError(str(task.get("errorMessage", task["state"])))
        if task["state"] == "succeeded":
            assets = output_assets(task)
            if assets and assets[0].get("unavailable"):
                raise RuntimeError("Output unavailable; keep the task ID for reconciliation.")
            if assets and assets[0].get("url") and not assets[0].get("pending"):
                return assets[0]
        time.sleep(5)
    raise TimeoutError("Rerun the same saved attempt to resume; no new task is needed.")

asset = run("bytedance/seedream-5.0-pro/text-to-image", {
    "prompt": "a folded paper map on a wooden table, overhead", "resolution": "1k", "output_format": "png"
}, "map-image")
print(asset["url"])

Die Antwort richtig lesen

Eine Aufgabe befindet sich immer in einem dieser Zustände: queued, running, succeeded, failed oder expired. Nur die ersten beiden laufen noch. Beenden Sie die Schleife daher, sobald der Zustand weder queued noch running ist, statt ausschließlich auf succeeded zu warten. Sonst wird eine fehlgeschlagene Aufgabe endlos abgefragt (ältere Datensätze können auch den nur lesbaren Zustand canceled enthalten). Der Ergebnislink steht unter output.assets[0].url. Bei direkten API-Aufrufen lesen Sie die Aufgabe aus dem data-Objekt der Antwortstruktur, nicht aus deren Wurzel. Eine bereits angenommene Aufgabe können Sie nicht abbrechen. Nur succeeded wird berechnet; bei failed und expired wird der reservierte Betrag normalerweise freigegeben.

Was eine Zeitüberschreitung für Ihre Anwendung bedeutet

HTTP 202 bedeutet, dass eine Aufgabe angenommen wurde, nicht dass die Generierung abgeschlossen ist. Eine lokale Zeitüberschreitung beendet das Warten; sie bricht die angenommene Aufgabe nicht ab. Bewahren Sie die Aufgaben-ID auf und setzen Sie die Aufgabe fort, statt eine weitere Generierung zu bezahlen. Die zurückgegebene Frist einer Aufgabe begrenzt die Wiederherstellung; sie sagt nicht vorher, wie lange das Rendern dauert.

  • Antwort auf die Übermittlung verloren: Bewahren Sie die Anfrage und ihren Schlüssel auf, damit bei der Wiederherstellung die ursprüngliche Aufgabe gefunden werden kann.
  • Generierung fehlgeschlagen: Zeigen Sie den Fehler des Modells an und lassen Sie den Nutzer bewusst einen weiteren Versuch wählen.
  • Generierung erfolgreich, Datei noch ausstehend: Warten Sie weiter auf diese Aufgabe; das Bild oder Video wird noch für die Auslieferung vorbereitet.

Eine neue Anfrage erhält einen neuen Idempotenzschlüssel. Bei der Wiederherstellung derselben Anfrage bleiben Schlüssel und Eingabe unverändert. Die Idempotenzreferenz beschreibt das Wiederholungsfenster von 24 Stunden.

Webhooks für den schnellen Weg nutzen

Senden Sie Abschlussereignisse an das Backend Ihrer Anwendung und aktualisieren Sie die Benutzeroberfläche anschließend über Ihren üblichen Benachrichtigungsweg. Ein Callback ist keine direkte Nachricht an den Browser des Nutzers.

Der Empfänger sollte vier Dinge erledigen:

  1. Das Ereignis mit dem offiziellen SDK und dem unveränderten Anfrageinhalt prüfen.
  2. Bestätigen, dass die Aufgabe zu einem Auftrag Ihrer Anwendung gehört.
  3. Das Ereignis dauerhaft speichern und Duplikate erkennen, bevor der Empfang bestätigt wird.
  4. Das Kopieren der Ausgabe und die Aktualisierung der Anwendung unabhängig von der HTTP-Antwort in eine Warteschlange stellen.

Geeignet, wenn: Sie bereits ein Backend betreiben und zeitnahe Abschlussmeldungen möchten. Eine andere Lösung wählen, wenn: es sich um ein kurzes lokales Skript ohne öffentlichen Empfänger handelt; Polling ist einfacher.

Prüfen Sie Aufgabenabschluss und Medienauslieferung getrennt. Ein korrekt aufgebautes Ereignis kann eine fehlgeschlagene Aufgabe beschreiben, während bei einer erfolgreichen Aufgabe noch Dateien verarbeitet werden müssen, bevor Ihre Anwendung sie als bereit meldet. Die Webhook-Dokumentation enthält die Vorgaben für Prüfung und Zustellung.

Einen regelmäßigen Abgleich beibehalten

Speichern Sie jede angenommene Aufgaben-ID. Prüfen Sie regelmäßig Aufgaben erneut, die Ihre Anwendung noch nicht abschließend bearbeitet hat, besonders nach einer Bereitstellung, einem Netzwerkausfall oder dem Wechsel des Signaturgeheimnisses. Leiten Sie ein wiederhergestelltes Ergebnis durch denselben idempotenten Abschlusshandler wie einen Webhook, damit die Galerie dieselbe Datei nicht zweimal erhält.

Belassen Sie ungeklärte Abrechnungsvorgänge im Journal, bis die Abrechnung abgeschlossen ist. Sind lokale Datensätze verloren gegangen, lassen sich die IDs über den Aufgabenverlauf des aktuellen Schlüssels wiederherstellen; die Produktionsintegration beschreibt diesen Weg.

Ergebnisse vor Ablauf kopieren

Links zu fertigen Ausgaben sind zeitlich begrenzt. Kopieren Sie die Dateien in einen Speicher unter Ihrer Kontrolle, mit einem User-Agent-Anfrageheader und einem Dateinamen, der zum zurückgegebenen Format passt. Ein fehlgeschlagener Download ist ein Anlass, das bestehende Ergebnis wiederherzustellen, nicht es neu zu generieren.

Unter Medienaufbewahrung und Auslieferung finden Sie die Fristen; dauerhafter Speicher erklärt den Kopierablauf.

Die Entscheidung

Beginnen Sie bei einem kleinen Skript mit SDK-Polling. Ergänzen Sie verifizierte Webhooks, sobald Sie einen interaktiven Dienst betreiben, und behalten Sie den regelmäßigen Abgleich zur Wiederherstellung bei. Die gespeicherte Aufgaben-ID verbindet alle drei Wege: Sie holen das Ergebnis einer einzigen Generierung ab, statt Ersatzaufgaben zu übermitteln.

Für mehr gleichzeitige Aufgaben ergänzen Sie eine begrenzte Stapelverteilung. Für Ihr erstes Bild-Video-Paar nutzen Sie die Einstiegsanleitung.

Den Aufruf einem Agent überlassen

Nutzen Sie einen Agent, wenn er die Eingaben vorbereiten und das Ergebnis zurückgeben soll, während Sie Preis und kreative Entscheidungen freigeben.

  • CLI: Speichern Sie {"prompt": "a folded paper map on a wooden table, overhead", "resolution": "1k", "output_format": "png"} als input.json und verwenden Sie dann npx @spicyapi/cli tasks create --model bytedance/seedream-5.0-pro/text-to-image --input-file input.json --wait. Die CLI lässt Sie den Preis bestätigen; bewahren Sie die zurückgegebene Aufgaben-ID für die Wiederherstellung auf.
  • MCP: Bitten Sie Ihren Assistenten, spicyapi_task_create für bytedance/seedream-5.0-pro/text-to-image und anschließend spicyapi_task_wait zu verwenden. Der MCP server fordert vor der Erstellung eine Preisbestätigung an.
  • Skill: Installieren Sie mit npx skills add spicyapi-ai/spicy-skill und bitten Sie dann $spicyapi, denselben Ablauf auszuführen und für Ihre Freigabe anzuhalten. Der Skill nutzt eine konfigurierte CLI- oder MCP-Verbindung.

Auch in English · 日本語 · 한국어 · Français · Español · Português (Brasil) · Русский · Italiano · Polski

Selbst ausprobieren

Sie zahlen nur für das, was Sie ausführen – ohne Tarif, ohne Abo.

Erstellt mit MiniMax H3 · ByteDance Seedance 2.0 Fast