# File d'attente, jobs longs et webhooks : ne plus attendre le GPU

> Routes /run et /status, états d'un job, durée de vie, délai d'exécution et webhook : piloter des jobs GPU de plusieurs minutes sur Runpod Serverless.


*Ou : comment déposer un travail au guichet, rentrer chez soi, et être sûr de récupérer le résultat.*

La réponse courte : sur un endpoint serverless Runpod, un job de plus d'une minute se lance sur la route asynchrone `/run`, qui renvoie aussitôt un identifiant. Le résultat se récupère ensuite par `/status`, ou arrive tout seul sur l'adresse d'un webhook. Quatre délais gouvernent le tout : dix minutes de calcul au plus par défaut, vingt-quatre heures de vie pour le job, trente minutes de conservation du résultat, et trois tentatives au total pour le webhook. Qui connaît ces quatre chiffres ne perd plus de job, et ce savoir vaut pour toute [l'architecture serverless sur GPU](/guides/gpu-cloud-ia/serverless-vs-pods-gpu/), images comme vidéo.

La route synchrone `/runsync` existe aussi, mais elle convient mal aux jobs longs. Elle attend 90 secondes par défaut, et garde le résultat une minute seulement : si la connexion tombe pendant l'attente, le job finit, il est facturé, et son résultat disparaît avant que vous puissiez le demander. Elle accepte en revanche des requêtes plus lourdes, 20 Mo contre 10 pour `/run`.

Sur le pipeline vidéo de ce site, chaque clip WAN 2.2 part sur `/run`, avec l'image source en base64 dans la requête, puis un script interroge `/status` toutes les quinze secondes. C'est simple, robuste, et suffisant pour une production par lots. [La documentation des requêtes](https://docs.runpod.io/serverless/endpoints/send-requests) détaille les autres routes, qui servent surtout quand quelque chose tourne mal.

> **Pour qui** : un développeur qui pilote des jobs GPU de plusieurs minutes, vidéo, entraînement court, traitement par lots, et ne veut ni bloquer son serveur ni perdre un résultat payé.
>
> **À partir de** : 0,00031 $ la seconde de RTX 4090 en serverless, 0,00044 $ pour une RTX 5090, facturées pendant le calcul, jamais pendant l'attente en file.
>
> **Pour démarrer** : ouvrir un compte Runpod, déployer un worker serverless, et soumettre les jobs sur `/run` avec un webhook et une politique de délais adaptée.

## Jobs asynchrones et webhooks sur GPU serverless : routes, états et délais

| Route | Rôle | À savoir |
|---|---|---|
| `POST /run` | soumet un job asynchrone | 10 Mo au plus, 1 000 requêtes par 10 secondes |
| `POST /runsync` | soumet et attend | 90 s d'attente par défaut, résultat gardé 1 minute |
| `GET /status/{id}` | état et résultat | résultat gardé 30 minutes après la fin |
| `GET /stream/{id}` | sortie progressive | pour les workers qui produisent par morceaux |
| `POST /cancel/{id}` | annule un job | 100 requêtes par 10 secondes |
| `POST /retry/{id}` | relance un job | seulement s'il est en échec ou hors délai, même identifiant |
| `POST /purge-queue` | vide la file | les jobs en attente seulement |
| `GET /health` | compteurs | jobs en file, workers actifs |

Un job passe par des états que [la documentation liste précisément](https://docs.runpod.io/serverless/endpoints/job-states) : `IN_QUEUE` tant qu'il attend un worker, `IN_PROGRESS` ou `RUNNING` pendant le calcul, puis `COMPLETED`, `FAILED`, `CANCELLED` ou `TIMED_OUT`. L'attente en file n'est pas facturée, le calcul l'est.

Deux délais se règlent job par job, dans un champ `policy` de la requête. Le délai d'exécution, dix minutes par défaut et jusqu'à sept jours, arrête un calcul qui s'éternise. La durée de vie, vingt-quatre heures par défaut, compte depuis la soumission, attente comprise : à son expiration, le job est supprimé et `/status` répond 404. Un troisième réglage, `lowPriority`, soumet un job qui ne déclenche pas le démarrage de nouveaux workers, utile pour du travail de fond qui peut attendre.

Voici la boucle du pipeline, réduite à l'essentiel, avec un webhook en plus :

```python
# Soumet un job en asynchrone, puis attend le résultat sans bloquer indéfiniment
import os
import time

import requests

BASE = f"https://api.runpod.ai/v2/{os.environ['RUNPOD_ENDPOINT_ID']}"
ENTETES = {"Authorization": f"Bearer {os.environ['RUNPOD_API_KEY']}"}


def soumettre(entree: dict) -> str:
    corps = {
        "input": entree,
        "webhook": "https://exemple.org/runpod/fin",  # prévenu à la fin, trois tentatives au total
        "policy": {"executionTimeout": 900_000, "ttl": 3_600_000},  # 15 min de calcul, 1 h de vie
    }
    r = requests.post(f"{BASE}/run", headers=ENTETES, json=corps, timeout=60)
    r.raise_for_status()
    return r.json()["id"]  # à enregistrer avant toute attente


def attendre(job_id: str, limite: int = 1800) -> dict:
    debut = time.time()
    while time.time() - debut < limite:
        time.sleep(15)
        s = requests.get(f"{BASE}/status/{job_id}", headers=ENTETES, timeout=30).json()
        if s["status"] == "COMPLETED":
            return s["output"]
        if s["status"] in ("FAILED", "CANCELLED", "TIMED_OUT"):
            raise RuntimeError(f"job {job_id} : {s['status']}")
    raise TimeoutError(f"job {job_id} toujours en cours, à reprendre par /status")
```

Le délai de la boucle, trente minutes, n'est pas choisi au hasard. Les premières scènes de la vidéo sur kDrive abandonnaient au bout de dix minutes, alors que certains jours un clip restait neuf à dix minutes en file avant d'être lancé. Ces clips finissaient quand même, facturés, et il fallait les rechercher à la main par leur identifiant, avant l'expiration des trente minutes de conservation. Les scènes suivantes attendent trente minutes. La leçon vaut pour tout job long : l'identifiant s'enregistre avant l'attente, et la limite de la boucle doit dépasser la pire file d'attente constatée, pas le temps de calcul moyen.

Le webhook, enfin, évite de garder un processus en attente. Runpod envoie le résultat à l'adresse indiquée dès la fin du job, et retente deux fois, à dix secondes d'intervalle, si votre serveur ne répond pas 200. Trois tentatives en vingt secondes, c'est peu : un redéploiement au mauvais moment suffit à les manquer. Gardez donc un polling de rattrapage pour les jobs sans nouvelles, tant que le résultat est conservé.

![Illustration : machine de laiton dans un hall sombre qui laisse rouler une bille de verre lumineuse dans un petit plateau en pleine lumière ambrée, une file de petites machines en attente au fond](/images/file-attente-jobs-asynchrones-webhooks-bille.original.webp "La bille compte plus que l'attente : sans elle, le résultat existe, mais personne ne sait où le chercher.")

### Si vous voulez le coût réel d'une production entière

84 clips WAN 2.2 pilotés par cette boucle, et la facture qui va avec, carte par carte, sont détaillés dans [le retour d'expérience d'un pipeline vidéo](/guides/gpu-cloud-ia/serverless-vs-pods-gpu/pipeline-video-gpu-serverless-retour-experience/).

### Si la file d'attente s'allonge

Des jobs qui restent longtemps en `IN_QUEUE` peuvent signaler un plafond de workers trop bas pour le rythme des soumissions, ou des cartes indisponibles. Le réglage est expliqué dans [combien de workers lancer](/guides/gpu-cloud-ia/serverless-vs-pods-gpu/autoscaling-workers-gpu-concurrence/).

### Si vous écrivez le worker qui reçoit ces jobs

Le handler reçoit le champ `input` de la requête et renvoie ce que `/status` restituera. Son écriture et son déploiement sont décrits dans [un worker serverless sur mesure](/guides/gpu-cloud-ia/serverless-vs-pods-gpu/worker-serverless-personnalise-docker/).


---

Cette page contient des liens d'affiliation. Si tu souscris via ces liens, je peux toucher une commission sans coût supplémentaire pour toi. Mon avis reste indépendant et basé sur mon usage réel des outils que je recommande.


---

**Tarifs :** prix relevés le 27 septembre 2026 sur les sites officiels des fournisseurs, dans la devise qu'ils affichent : dollars américains pour les plateformes américaines, euros hors taxes pour les européennes. Les tarifs du GPU bougent souvent, et sur une place de marché chaque hôte fixe son prix : les montants cités peuvent avoir changé depuis cette date.

