HiAPI
Blog

Tutoriel

hiapi /v1/tasks : tâche bloquée ou expirée : diagnostic et stratégie de réessai

Oct 13, 2026
hiapi /v1/tasks : tâche bloquée ou expirée : diagnostic et stratégie de réessai

Vous avez soumis une tâche via POST https://api.hiapi.ai/v1/tasks, obtenu un taskId, mais lorsque vous interrogez GET /v1/tasks/{taskId}, data.status reste bloqué sur queued ou handling depuis plusieurs minutes — elle semble « bloquée » ; ou bien votre boucle de polling a atteint la limite que vous avez fixée sans jamais obtenir d'état terminal, et vous avez signalé un timeout. Ne vous précipitez pas sur un renvoi : les tâches hiapi sont asynchrones, « pas encore terminée » et « déjà en échec » sont deux choses différentes ; diagnostiquez d'abord pour éviter d'aggraver la situation.

Si vous voyez data.status déjà à fail, error.code à TASK_TIMEOUT, ou un HTTP 504 littéral levé par le navigateur/proxy — c'est un autre type de problème (la tâche a réellement échoué, ou le timeout se situe au niveau réseau entre vous et hiapi) ; consultez Dépannage des timeouts et erreurs 504 des tâches HiAPI. Cet article ne traite que des scénarios de « blocage » où la tâche tarde à atteindre un état terminal.

Symptômes du problème

Une tâche « bloquée » renvoie à peu près ceci lors de la requête (HTTP 200, mais la tâche est toujours dans un état non terminal) :

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

Caractéristique clé : data.status vaut queued (en file d'attente) / handling (en traitement) / archiving (en archivage), data.error est null, et data.output est encore vide. Cela signifie que la tâche est saine, simplement pas encore terminée.

hiapi ne compte que deux états terminaux pour une tâche : data.status à success ou fail. Tant qu'il n'est pas l'un de ces deux, la tâche n'est pas terminée — les « blocages » se produisent presque toujours dans cette phase non terminale.

Deux « faux blocages » faciles à confondre :

  • La requête renvoie directement 404 :

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

    Ce n'est pas un blocage : soit le taskId est erroné, soit la tâche n'a jamais été créée, soit l'enregistrement de la tâche a expiré — vérifiez le data.taskId obtenu lors de la soumission.

  • Rejet synchrone dès la soumission (aucun taskId obtenu), par exemple un model incorrect :

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

    Ce type de cas relève d'un problème de requête lui-même, pas d'une tâche bloquée ; corrigez et soumettez à nouveau.

Causes fréquentes (par ordre de probabilité)

1. Encombrement de la file d'attente (la plus fréquente)

Lorsqu'un modèle (modèle d'image, de vidéo, ou tout modèle à forte charge de calcul) est massivement sollicité, votre tâche patiente dans la file d'attente de ce modèle jusqu'à être prise par un worker.

  • Signal : data.status est queued, data.error est null, et peu de temps s'est écoulé depuis la soumission.
  • Correctif : ralentissez le rythme de polling, une requête toutes les 5–10 secondes suffit, n'enchaînez pas à 100 ms. La plupart des tâches sont prises en une à deux minutes.

2. Les modèles lourds sont intrinsèquement longs

La tâche a déjà été prise (handling/archiving), mais ce modèle est naturellement lent à s'exécuter — les vidéos longues, les hautes résolutions et les images de référence multiples allongent significativement la durée.

  • Signal : data.status est handling ou archiving depuis plusieurs minutes, sans erreur.
  • Correctif : accordez une limite de polling plus large aux tâches lourdes (prévoyez une marge selon les capacités du modèle). Longue durée ≠ échec, ne coupez pas juste avant le résultat.

3. Un polling mal configuré (la cause la plus souvent confondue avec un « blocage »)

Beaucoup de « blocages » sont en réalité des problèmes côté client : un intervalle de polling trop court qui vous fait tourner en rond, l'absence de limite, ou une limite trop courte qui abandonne trop tôt.

  • Signal : le data.status côté serveur progresse normalement, mais votre boucle a levé un timeout prématurément, ou vous ne lisez pas du tout data.status.
  • Correctif : utilisez un intervalle fixe (5 secondes recommandées) + une limite raisonnable (environ 10 minutes pour une tâche standard, plus pour les tâches lourdes). Le timeout doit être déterminé par votre boucle, et non par un état timeout côté serveur — hiapi ne possède pas cet état.

4. Le point de terminaison de callback est injoignable

Si vous avez fourni un callback lors de la soumission, la tâche elle-même peut déjà être success, mais le résultat n'atteint pas votre endpoint, d'où une impression de « silence ».

  • Signal : une requête active montre data.status déjà à success, data.output contient des données, mais votre endpoint de callback n'a rien reçu.
  • Correctif : l'adresse de callback doit être accessible publiquement, recevoir des POST, et renvoyer un 2xx en environ 10 secondes ; sinon, passez au polling. Détails dans Pourquoi le callback des tâches hiapi ne se déclenche pas.

Étapes de correction

  1. Consultez d'abord l'état, ne renvoyez pas au feeling : GET /v1/tasks/{taskId}, lisez data.status et data.error.
  2. Aiguillez selon l'état :
    • queued / handling / archiving → toujours en cours, attendez 5–10 secondes avant de revérifier (causes 1 / 2).
    • success → tâche réussie, récupérez le résultat dans data.output ; si vous attendiez un callback qui n'arrive pas → cause 4.
    • fail → lisez data.error.code et data.error.message ; si c'est TASK_TIMEOUT → voir le guide sur les timeouts et les 504.
    • 404 task not found → le taskId est erroné ou la tâche n'a pas été créée ; vérifiez le data.taskId dans la réponse de soumission.
  3. L'output a une durée de validité : l'URL de téléchargement dans data.output porte un expireAt (environ 7 jours) ; une fois obtenue, enregistrez-la / transférez-la rapidement, ne conservez pas de lien à chaud à long terme.
  4. Vérifiez qu'il ne s'agit pas d'un problème d'authentification / de requête : exécutez d'abord l'exemple de vérification minimal ci-dessous, pour écarter un problème de key ou de model id.
  5. Si vous devez vraiment réessayer, usez du backoff : voir la section suivante sur la stratégie de réessai, ne renvoyez pas le même body en boucle serrée.

Exemple de vérification minimal

Utilisez une requête minimale pour confirmer que la key et l'interface de tâches fonctionnent. Utilisez l'id brut du model (ex. : 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" }
  }'

Une soumission réussie renvoie une réponse du type {"data":{"taskId":"…","status":"queued"}}. Interrogez avec le taskId :

curl -s "https://api.hiapi.ai/v1/tasks/<taskId>" \
  -H "Authorization: Bearer $HIAPI_API_KEY"
  • Si la réponse est 401 avec un body {"error":{"code":"permission_denied","type":"hiapi_error","request_id":"…"}} — le problème vient de la key, pas de la tâche. Consultez d'abord Dépannage de l'erreur API Key invalide.
  • Si la soumission est rejetée par 400 + "error_code":"MODEL_UNAVAILABLE" — c'est un problème de model id. Passez l'id brut et reportez-vous à Erreur hiapi « modèle indisponible ».

Stratégie de réessai sans aggravation

  1. Backoff exponentiel : 5s → 15s → 45s recommandés.
  2. Plafond de 3 tentatives : après un troisième échec, escaladez (changer de modèle, réduire la configuration, ou ouvrir un ticket), ne bouclez pas indéfiniment.
  3. Chaque réessai est une nouvelle tâche : un POST /v1/tasks correspond à un nouveau taskId et peut générer une nouvelle facturation. hiapi ne promet pas de « re-soumission idempotente » — ne comptez pas sur le renvoi du même body pour réutiliser l'ancienne tâche.
  4. En cas de 429, ralentissez le débit de soumission, pas le débit de polling : voir Comment corriger l'erreur de limitation de débit (429) hiapi.

Un exemple Python fiable de 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 → continuer d'attendre
    raise TimeoutError(f"task {task_id} 在 {max_wait}s 内未到终态")

Notez que la détermination de l'état terminal ne reconnaît que success et fail ; tous les autres états (queued / handling / archiving) imposent de continuer d'attendre, et le timeout est déterminé par votre max_wait.

Quand escalader

  • Réessai avec backoff 3 fois, chaque fois le même data.error.code → pas une secousse transitoire, changez l'entrée ou de modèle.
  • La tâche reste longtemps en queued sans aucune progression → consultez la console hiapi pour voir s'il y a des notifications de plateforme, et ouvrez un ticket avec le request_id.
  • data.status est déjà success mais le callback n'arrive jamais → ne reposez plus sur le callback pour cet endpoint, passez au polling.

Liens internes associés

FAQ

Q : À partir de quand parle-t-on de « timeout » ? Existe-t-il une durée de timeout uniforme ? R : Il n'y a pas de chiffre uniforme, cela dépend du modèle ; les tâches lourdes (vidéo longue, haute résolution) prennent plus de temps. De plus, hiapi n'a pas d'état timeout côté serveur — le timeout est généralement l'atteinte de la limite que votre boucle de polling s'est fixée. Une tâche réellement expirée côté serveur aura data.status:"fail" + error.code:"TASK_TIMEOUT" ; dans ce cas, voir le guide sur les timeouts et les 504.

Q : La tâche est queued depuis 30 secondes, faut-il annuler et réessayer ? R : Non. 30 secondes est dans la norme pour tout modèle non trivial ; attendez au moins deux minutes avant d'envisager un réessai.

Q : Peut-on annuler une tâche en cours d'exécution ? R : L'annulation n'est généralement pas prise en charge ; même si elle l'était, la file d'attente / le slot de calcul est souvent déjà occupé. Laisser la tâche se terminer et récupérer le résultat est plus avantageux.

Q : La même requête fonctionnait hier, mais est bloquée aujourd'hui ? R : Dans la grande majorité des cas, il s'agit d'un encombrement de la file d'attente du modèle (cause 1). Changez pour un modèle aux capacités similaires, ou attendez 5–10 minutes que la file se résorbe avant de réessayer.

Q : Toutes les tâches expirent, est-ce un problème de mon compte ? R : Consultez d'abord la console hiapi pour vérifier s'il y a des notifications au niveau du compte, puis confirmez si vous êtes soumis à une limitation de débit (voir le guide 429). Si tout est normal et qu'un seul modèle échoue, il s'agit probablement de la file d'attente ou du backend de ce modèle, pas de votre compte.

Q : Réessayer une tâche bloquée / expirée entraîne-t-il une double facturation ? R : Chaque POST /v1/tasks est une nouvelle tâche facturable. Une tâche en échec sans résultat n'est généralement pas facturée en production, mais la file d'attente / le slot de calcul peut déjà être occupé. Si le coût vous importe, vérifiez a posteriori sur la page d'utilisation.

Articles similaires

Voir tous les articles →

Commencez avec des artefacts IA persistants

Obtenez votre clé API et appelez des modèles d'image, de vidéo et d'audio via une API unique basée sur les tasks.

Lire la documentation de l'API