Modèle asynchrone et codes de retour ==================================== Toute création et toute suppression sont **asynchrones**. C'est le point qui surprend le plus souvent à l'intégration : un ``202`` ne dit pas que la ressource existe, il dit que la demande a été acceptée et enregistrée. Les deux temps d'une requête ---------------------------- .. mermaid:: sequenceDiagram participant C as Appelant participant A as API participant W as Worker C->>A: POST /subnets A->>A: Prepare — valide, écrit "creating" A-->>C: 202 + ressource en creating A->>W: Dispatch (file d'attente) W->>W: Execute — netns, netif, dnsmasq W->>W: état → running (ou error) C->>A: GET /subnets/ A-->>C: 200 + state **Prepare** est synchrone, dans le handler HTTP : il valide l'état, écrit l'état initial en base et répond. **Execute** est asynchrone : il fait le travail réseau réel, puis positionne l'état final. Conséquence directe : un échec d'``Execute`` ne peut pas être remonté dans la réponse HTTP. Il se lit dans l'état de la ressource, qui passe à ``error``. Attendre correctement --------------------- Il n'y a pas de webhook ni de long-polling : l'appelant interroge ``GET //`` jusqu'à un état stable. .. code-block:: bash until [ "$(curl -sf http://127.0.0.1:8080/subnets/sn-000001 | jq -r .state)" = running ]; do sleep 2 done Trois règles pour un appelant robuste : * **Toujours borner l'attente.** Côté agent, ``dispatcher.timeout_seconds`` (300 s par défaut) borne les opérations qui attendent une transition ; l'appelant doit avoir sa propre borne. * **Traiter ``error`` comme terminal, pas comme un échec transitoire.** Un ``Execute`` en échec ne se rejoue pas tout seul. * **Ne pas enchaîner sans vérifier.** Créer un subnet dont le VPC est encore en ``creating`` échoue en 422 ; démarrer une VM sur un subnet en ``creating`` ou ``running`` est en revanche accepté. Codes de retour --------------- .. list-table:: :header-rows: 1 :widths: 12 88 * - Code - Signification * - ``202`` - demande acceptée et enregistrée ; l'état passera à ``running`` ou ``error`` * - ``200`` - lecture réussie (``GET``) * - ``400`` - champ obligatoire manquant, corps invalide, ``iface_type`` inconnu, base64 invalide * - ``404`` - ressource inexistante * - ``409`` - conflit d'existence ou d'état : ressource déjà créée, ou suppression depuis un état qui ne l'autorise pas ; pour un VPC, subnets encore présents * - ``422`` - dépendance absente ou pas prête : VPC parent d'un subnet, subnet d'une VM * - ``500`` - erreur interne Le corps d'erreur est uniforme : ``{"error": "…"}``. Idempotence ----------- Les créations ne sont **pas** idempotentes : recréer une ressource existante donne 409, pas 202. Un appelant qui rejoue une requête après un timeout réseau doit donc traiter 409 comme « déjà fait », après avoir vérifié l'état par un ``GET``. Les suppressions depuis l'état ``error`` sont acceptées mais **best-effort** : les ressources système peuvent n'avoir été créées que partiellement, et il n'y a pas de rollback — voir :doc:`/concepts/cycle-de-vie`.