CodeGym /Cours /ChatGPT Apps /Tests de charge légers et qualité des données du flux

Tests de charge légers et qualité des données du flux

ChatGPT Apps
Niveau 17 , Leçon 4
Disponible

1. Pourquoi l’application ChatGPT a‑t‑elle besoin de tests de charge ?

Dans le web classique, le test de charge est souvent associé à l’image « des millions de RPS, un cluster géant, des pizzas pour les SRE ». Pour une application ChatGPT et des serveurs MCP, la réalité est plus simple et, heureusement, moins chère. Vous connaissez déjà les SLO, mais voyons comment SLO/observabilité et qualité du flux interagissent sous charge.

La particularité principale : ChatGPT attend la fin d’un tool call pour continuer à générer la réponse. L’utilisateur voit un joli flux de tokens, mais dès que le modèle décide d’appeler un outil, la magie du streaming s’arrête — jusqu’à ce que le backend réponde. Si votre serveur MCP ou ACP répond parfois en 8–10 s au lieu de l’objectif 2–4 s, l’UX passe de « assistant magique » à « encore un site lent ».

Il y a en plus un budget de timeout strict : pour les appels d’outils, OpenAI fixe une borne supérieure de l’ordre de dizaines de secondes (les valeurs exactes dépendent du mode, mais pensez en 30–60 s, et côté UX — plutôt 5–10 s). Si, au pic de charge, vos tool calls se mettent soudainement à prendre 25–30 s, vous êtes formellement dans la limite, mais du point de vue de l’utilisateur, vous êtes déjà « cassés ».

Deuxième point : ce qui nous importe n’est pas tant une RPS abstraite que la simultanéité. Pour une app issue du Store, il est réaliste d’avoir 50–100 utilisateurs actifs en parallèle ; c’est précisément cela qu’il faut vérifier, et non « si un GET /health synthétique tient 50k RPS ».

Enfin, une application ChatGPT — c’est une pile :

flowchart LR
  User --> ChatGPT
  ChatGPT -->|tools/call| MCP["Serveur MCP GiftGenius"]
  MCP --> DB["Base du flux de cadeaux"]
  MCP --> ACP["Checkout / backend ACP"]
  ACP --> PSP["PSP / Stripe"]

Si nous ne vérifions pas comment cette pile se comporte sous une charge faible mais réaliste, toute campagne promo ou mise en avant dans le Store peut rapidement se transformer en diapositive « comment ne pas faire des produits LLM ».

Dans cette leçon, par « tests de charge légers », nous entendrons des exécutions courtes (généralement 1–10 minutes) qui vérifient :

  • si le système supporte le pic d’audience attendu ;
  • si la latence p95/p99 ne dépasse pas les SLO ;
  • s’il n’y a pas de rafales d’erreurs, de timeouts et de rate limits des API externes.

En parallèle, nous regarderons l’autre côté de la qualité — les données du flux produits (product feed, ci‑après simplement « flux »), sans lesquelles aucun GiftGenius ne sera ni « Gift », ni « Genius ».

Dans cette leçon, nous commencerons par les tests de charge légers pour MCP/ACP (quoi charger et comment, quelles métriques observer), puis nous l’ancrerons dans l’observabilité (latence, erreurs, ressources, webhooks et logs), et dans la deuxième partie, nous parlerons de la qualité du flux et de la façon dont elle peut surprendre sous charge.

2. Que charger précisément : pas ChatGPT, mais vos API

Il est important de fixer une idée pour éviter toute confusion par la suite : nous réalisons le test de charge directement sur notre backend — serveur MCP, endpoints ACP, webhooks — et non via l’UI de ChatGPT.

Plusieurs raisons à cela.

  • Premièrement, l’économie. Si vous faites transiter de vrais tool calls via ChatGPT, vous paierez des tokens tout en vous heurtant aux limites de ChatGPT, alors que vous testez votre code.
  • Deuxièmement, la prédictibilité. Avec des appels directs à /mcp ou /api/checkout, vous contrôlez le scénario sans dépendre des décisions du modèle — à savoir s’il va appeler cet outil ou non.
  • Troisièmement, la transparence. Sous charge, vous voulez voir clairement : voici 2000 requêtes vers MCP en 5 minutes, voici la distribution de latence, voici le graphe CPU. En faisant passer la charge via ChatGPT, une couche supplémentaire de bruit et de limites ne fera que brouiller le tableau.

Jeu typique d’endpoints pour un test de charge GiftGenius :

  • l’endpoint du serveur MCP qui implémente des outils JSON‑RPC (/mcp ou équivalent) ;
  • un ou deux endpoints ACP pour créer et finaliser un checkout (en mode sandbox de la passerelle de paiement) ;
  • éventuellement — l’endpoint qui traite les webhooks de la passerelle de paiement, pour voir son comportement lors d’un pic d’événements.

Nous supposerons que nous avons un backend Next.js 16 hébergeant le serveur MCP, accessible via /api/mcp, et un serveur ACP avec l’endpoint /api/checkout/create.

3. Mini‑scénario de smoke‑load pour GiftGenius

Imaginons que nos product managers croient en un bel avenir et disent : « Un pic réaliste — 50 utilisateurs simultanés, chacun entre, choisit un cadeau et arrive parfois jusqu’au paiement. »

Pour un test de charge léger, il suffit de modéliser, disons, 30–50 « utilisateurs virtuels » (VU), chacun exécutant la séquence suivante :

  1. Appel de l’outil giftgenius.search_gifts (recherche de cadeaux par profil et budget).
  2. Appel de giftgenius.get_gift_details pour deux produits du résultat.
  3. (Parfois) appel de l’endpoint ACP create_checkout_session pour un produit.

Tout cela directement en HTTP vers notre MCP/ACP, sans ChatGPT.

Appel JSON‑RPC vers MCP

Exemple de corps de requête vers MCP (simplifié) :

const body = {
  jsonrpc: "2.0",
  id: "test-" + Math.random(),
  method: "tools/call",
  params: {
    toolName: "giftgenius.search_gifts",
    arguments: {
      occasion: "birthday",
      budget: 50,
      interests: ["sport", "books"],
    },
  },
};

Dans un projet réel, la structure peut légèrement différer, mais le principe est le même : une méthode JSON‑RPC, à l’intérieur — l’outil et ses arguments.

4. Écrire un petit script de charge en TypeScript

En première étape, implémentons la partie la plus simple de notre scénario — l’appel à giftgenius.search_gifts sur MCP. Commençons par un script Node.js minimal en TypeScript, qui envoie ces requêtes à /api/mcp et mesure la latence, puis nous ajouterons le checkout et des parcours plus complexes.

Client HTTP de base

Supposons que nous ayons un .env avec MCP_URL=http://localhost:3000/api/mcp.

// scripts/loadTest.ts
import "dotenv/config";

const MCP_URL = process.env.MCP_URL!;

async function callSearchGifts() {
  const body = {
    jsonrpc: "2.0",
    id: `search-${Date.now()}-${Math.random()}`,
    method: "tools/call",
    params: {
      toolName: "giftgenius.search_gifts",
      arguments: { occasion: "birthday", budget: 50 },
    },
  };

  const started = Date.now();
  const res = await fetch(MCP_URL, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(body),
  });
  const latencyMs = Date.now() - started;
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return latencyMs;
}

On peut ajouter ici un parsing simple de la réponse JSON, mais pour la latence/le taux d’erreur, cela suffit.

Lancement concurrent de plusieurs requêtes

Nous devons contrôler le nombre de requêtes simultanées. Pour faire simple, prenons un nombre fixe « d’utilisateurs virtuels » et demandons à chacun d’effectuer N requêtes à la suite.

async function runVirtualUser(iterations: number) {
  const latencies: number[] = [];
  for (let i = 0; i < iterations; i++) {
    try {
      const ms = await callSearchGifts();
      latencies.push(ms);
    } catch (e) {
      console.error("Error in VU:", e);
      latencies.push(-1); // marquer l'erreur
    }
  }
  return latencies;
}

On peut maintenant lancer, par exemple, 20 utilisateurs virtuels :

async function main() {
  const users = 20;
  const iterations = 10;

  const tasks = Array.from({ length: users }, () =>
    runVirtualUser(iterations),
  );

  const results = await Promise.all(tasks);
  const all = results.flat();
  // ...calcul des métriques
}

main().catch((e) => console.error(e));

Cela générera déjà environ 200 appels à MCP, dont une partie s’exécutera en parallèle, c’est‑à‑dire avec une simultanéité suffisamment élevée.

Calcul de p95 et du taux d’erreur

Ajoutons un petit utilitaire pour calculer le percentile et les erreurs. Rappel : p95 est la valeur en dessous de laquelle 95 % des requêtes se placent.

function percentile(values: number[], p: number) {
  const sorted = values.filter(v => v >= 0).sort((a, b) => a - b);
  if (!sorted.length) return 0;
  const idx = Math.floor((p / 100) * (sorted.length - 1));
  return sorted[idx];
}

function errorRate(values: number[]) {
  const total = values.length;
  const errors = values.filter(v => v < 0).length;
  return (errors / total) * 100;
}

Et dans main, ajoutons l’affichage :

const p95 = percentile(all, 95);
const p99 = percentile(all, 99);
const errRate = errorRate(all);

console.log(`Total: ${all.length}`);
console.log(`p95: ${p95} ms, p99: ${p99} ms`);
console.log(`Error rate: ${errRate.toFixed(2)}%`);

Vous disposez maintenant d’un script smoke‑load minimal, exécutable en local ou sur un staging avant la release. Vous ne touchez pas à ChatGPT, vous n’usez pas de tokens, et toute l’attention est sur votre MCP.

Que faire avec l’ACP et le checkout

De la même manière, vous pouvez ajouter un helper callCreateCheckoutSession qui ciblera l’endpoint ACP. Il est important d’utiliser le mode test/sandbox de la passerelle de paiement pour ne pas générer de vraies commandes. L’appel typique sera un POST JSON classique :

async function callCreateCheckoutSession(productId: string) {
  const started = Date.now();
  const res = await fetch("http://localhost:3000/api/checkout/create", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ productId, test: true }),
  });
  const latencyMs = Date.now() - started;
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return latencyMs;
}

Ensuite, dans runVirtualUser, vous pouvez adopter le pattern : 3 recherches → 1 checkout, pour simuler l’entonnoir « plus de recherches que d’achats ».

5. Outils plus costauds : k6 (mais en mode simple)

Un script Node est très bien comme « entrée minimale », mais il peut être pratique d’utiliser un outil spécialisé comme k6, où les scénarios s’écrivent en JavaScript et le runtime est en Go (donc rapide).

Exemple de petit script k6 pour MCP :

// loadtest-mcp.js
import http from "k6/http";
import { check, sleep } from "k6";

export const options = {
  stages: [
    { duration: "30s", target: 30 },
    { duration: "2m", target: 30 },
  ],
};

export default function () {
  const payload = JSON.stringify({
    jsonrpc: "2.0",
    id: `search-${Math.random()}`,
    method: "tools/call",
    params: {
      toolName: "giftgenius.search_gifts",
      arguments: { occasion: "birthday", budget: 50 },
    },
  });

  const res = http.post(__ENV.MCP_URL, payload, {
    headers: { "Content-Type": "application/json" },
  });

  check(res, { "status is 200": (r) => r.status === 200 });
  sleep(1);
}

Commande d’exécution :

MCP_URL=http://localhost:3000/api/mcp k6 run loadtest-mcp.js

k6 calcule lui‑même p95/p99 et le taux d’erreur, et génère de jolis rapports — que vous pouvez ensuite exporter vers Grafana et d’autres systèmes.

Important : même avec de tels outils, notre objectif reste le même : ne pas tenir un million de RPS, mais s’assurer qu’à 5–10× le pic attendu, le système ne s’effondre pas et que le p95 reste dans les limites des SLO.

6. Que regarder pendant (et après) un run de charge

Nous avons déjà discuté des métriques et des SLO, ancrons‑les maintenant dans le contexte de charge.

Premièrement, la latence. Pour des outils MCP du type search_gifts, vous vous êtes fixé une cible du genre « p95 < 2–3 s ». Pendant le smoke‑load, regardez si p95/p99 ne grimpent pas d’un facteur 2–3. Comparez au baseline : si avant un changement de code la p95 était à 400 ms, et après — à 1500 ms, même si vous êtes formellement dans les SLO, c’est déjà un signal d’alerte.

Deuxièmement, le taux d’erreur. Sous charge, surgissent souvent des surprises : pool de connexions DB épuisé, 429 inattendus d’une API externe, timeouts en appelant la passerelle de paiement. À charge normale, le taux d’erreur doit être proche de zéro ; en smoke‑load, quelques échecs isolés sont acceptables, mais sûrement pas 5–10 %.

Troisièmement, les métriques de ressources : CPU, mémoire, parfois — nombre de descripteurs de fichiers et de connexions ouverts. Elles dépendent de votre infrastructure, mais l’idée clé est simple : vous ne voulez pas voir, à 30 VU, un CPU à 100 % et un GC qui consomme la moitié du temps.

Quatrièmement, les webhooks. Si vous avez un scénario e‑commerce, le point final de la commande dépend souvent du traitement réussi d’un webhook de la solution de paiement. Il est important de regarder non seulement la vitesse de la requête côté ACP, mais aussi le délai « webhook reçu → traitement réussi ».

Enfin, les logs. Des logs structurés avec trace_id/checkout_session_id permettent, après un run de charge, de prendre quelques requêtes les plus lentes ou en échec et de suivre la chaîne : MCP → API externe → ACP → webhook. C’est particulièrement utile si, sous charge, vous voyez des queues étranges sur le p99.

7. Qualité des données du flux : de la structure au sens

Nous avons vu comment, sous charge, se comportent latence, erreurs et ressources. Mais même si vous respectez vos SLO sur ces aspects, l’expérience utilisateur peut tout de même « s’effriter » à cause de mauvaises données.

Passons au deuxième grand thème : les données. Dans une app e‑commerce comme GiftGenius, le product feed (flux de produits) — ce n’est pas « un fichier sur disque », c’est littéralement le carburant des LLM et des agents. Si le flux est sale, le modèle n’inventera pas pour vous le prix ou la disponibilité.

Il est pratique de penser la qualité du flux en trois couches.

Niveau structurel

Il s’agit de la validité de base des données :

  • Le JSON se parse correctement.
  • Tous les champs obligatoires sont présents : id, name, price, currency, imageUrl, availability, etc.
  • Les types de valeurs correspondent aux attentes : le prix — un nombre, availability — un enum, categories — un tableau de chaînes.
  • Pas de doublons de id.

Vous avez déjà couvert une partie avec des tests de contrat, en décrivant un JSON Schema/schéma Zod pour le flux. Il faut maintenant appliquer ces schémas à des volumes réels de données.

Exemple de schéma Zod simple pour un élément du flux GiftGenius :

import { z } from "zod";

export const giftItemSchema = z.object({
  id: z.string().min(1),
  name: z.string().min(3),
  description: z.string().optional(),
  price: z.number().positive(),
  currency: z.enum(["USD", "EUR", "GBP"]),
  imageUrl: z.string().url(),
  inStock: z.boolean(),
  tags: z.array(z.string()).default([]),
});

Et le schéma du flux entier — tout simplement z.array(giftItemSchema).

Niveau métier (sémantique)

Structurellement, un produit peut être valide mais, métierment, absurde :

  • Prix à 0 ou 0,01 pour un produit cher.
  • Devise qui ne correspond pas au marché (USD pour des produits vendus uniquement en EUR).
  • inStock = true, mais la date de dernière mise à jour remonte à six mois.
  • Catégories au nombre de 1000 sans aucune uniformisation.

Pour ce niveau, il est utile d’ajouter des vérifications supplémentaires et des « règles de bon sens ». Par exemple :

const businessRules = (item: GiftItem) => {
  const problems: string[] = [];

  if (item.price > 10000) {
    problems.push("prix anormalement élevé");
  }
  if (!item.inStock && item.tags.includes("bestseller")) {
    problems.push("best-seller mais pas en stock");
  }
  return problems;
};

Ces vérifications peuvent être exécutées dans un job nocturne ou lors de la génération d’un nouveau flux.

Niveau LLM

Le modèle est très puissant, mais il a ses propres « travers » :

  • Description remplie de HTML, de balises inutiles et de texte technique.
  • Mélange des langues (moitié du flux en anglais, moitié en une autre langue) sans indication de locale.
  • Noms « SEO » beaucoup trop longs du style « Acheter le meilleur super cadeau pas cher ».

À ce niveau, il faut mettre les données dans un format convivial :

  • Retirer les balises HTML ou les convertir en texte brut.
  • Normaliser la langue des descriptions (ou au moins indiquer explicitement la locale).
  • Rogner les noms excessivement longs et les informations dupliquées.

Ces tâches peuvent être partiellement automatisées (par exemple, via des scripts de pré‑traitement), et partiellement réglées avec l’équipe qui alimente le flux.

8. Pratique : validateur de flux pour GiftGenius

Ajoutons à notre projet un simple script validateFeed.ts, qui lira un JSON de flux, le validera via Zod et calculera des métriques de qualité de base.

// scripts/validateFeed.ts
import { readFile } from "fs/promises";
import { giftItemSchema } from "../src/schema/giftItem";

async function main() {
  const raw = await readFile("data/gift-feed.json", "utf-8");
  const data = JSON.parse(raw);

  const items = giftItemSchema.array().parse(data);
  console.log(`Nombre total d'articles: ${items.length}`);

  const missingImages = items.filter(i => !i.imageUrl).length;
  console.log(`Sans images: ${missingImages}`);
}

main().catch((e) => {
  console.error("Feed validation failed:", e);
  process.exit(1);
});

Ici, nous utilisons le même contrat que le serveur MCP, c’est‑à‑dire tests de contrat et vérification du flux utilisent le même schéma — cela réduit fortement le risque d’écarts.

Ensuite, vous pouvez ajouter des vérifications métier et des métriques du type :

  • part des produits sans description ;
  • part des produits avec un prix suspectement bas/élevé ;
  • nombre de doublons de id ou de combinaisons name + price répétées.

Ces chiffres peuvent être envoyés vers votre système de métriques (Prometheus, Datadog, etc.) et vous pouvez leur associer des SLO de qualité de données — de la même façon que vous définissez des SLO pour le code.

9. Comment charge et flux sont liés

On a parfois l’impression que « performance » et « qualité des données » sont deux sujets peu liés. En pratique, ils sont assez étroitement imbriqués.

Exemples de liens :

  • Sous charge, une partie des requêtes emprunte des branches « rares » de la logique, peu rencontrées auparavant. Par exemple, des produits avec des types de remises spéciaux ou un shipping atypique. Si le flux est sale à ces endroits, vous pouvez obtenir et des erreurs, et une forte dégradation de performance (beaucoup de validations, d’exceptions, de logiques de repli).
  • Si le flux est très bruyant (descriptions énormes avec du HTML, tags inutiles), le serveur MCP doit transférer et sérialiser plus de données, ce qui impacte directement le temps de traitement d’un tool-call et la taille de la réponse.
  • Côté e‑commerce, un flux de mauvaise qualité peut entraîner de nombreuses tentatives de checkout « à vide », quand l’utilisateur choisit un produit soudainement hors stock. Cela affecte l’UX et les métriques ACP (hausse des intents non aboutis).

Il est pratique de voir cela comme une matrice :

Problème du flux Symptôme sous charge Où regarder
Prix/devise incohérents Erreurs côté ACP, paiements refusés Logs ACP + SLO checkout
Doublons de produits Résultats de recommandation étranges, appels superflus Logs MCP, métriques UX
Absence d’images/descriptions Le modèle donne des recommandations « plates » Logs App + retours UX
HTML/bruit dans les descriptions Sérialisations lentes, payloads volumineux Latence MCP

Le run de charge joue ici le rôle d’une lampe torche : il aide à mettre en lumière les zones du flux rarement touchées en temps normal, mais qui commencent à « tirer » avec du trafic actif.

10. Intégrer cela dans le processus de release de GiftGenius

Côté processus, tout ce qui précède ne doit pas être « une fois avant le premier prod ». Dans le plan pédagogique des modules 16 (« Production, réseau et montée en charge ») et 17 (« Observabilité et qualité »), cette approche est conçue comme une partie du checklist de release : avant la mise en production, vous lancez non seulement des tests unitaires/contrat/E2E, mais aussi un court smoke‑load plus une vérification du flux.

Pipeline minimal raisonnable avant déploiement d’une nouvelle version :

  1. Unit + contrat + tests d’intégration au vert.
  2. Court smoke‑load contre MCP/ACP sur staging si du code critique a changé (logique de recherche, accès DB, checkout).
  3. Le validateur de flux passe sans erreurs, les métriques de base du flux (nombre d’entrées corrompues, part sans images, etc.) sont dans les limites acceptables.
  4. Tableaux de bord et alertes mis à jour en tenant compte des nouveaux endpoints et SLO.
  5. Plan de rollback prêt en cas d’échec : désactivation via feature flag ou retour au build précédent.

Ainsi, votre GiftGenius cesse d’être « une démo pour le DevDay » et devient un service prêt pour la vie dans le Store et les pics de trafic.

11. Erreurs typiques lors des tests de charge et de la vérification du flux

Erreur n°1 : test de charge « via ChatGPT » au lieu de votre backend.
Parfois on veut « tester comme en réalité » et on lance des scripts qui passent par l’UI de ChatGPT. Résultat : on se heurte aux limites d’OpenAI, on brûle des tokens et on obtient des résultats très bruyants. Alors que les problèmes MCP/ACP pouvaient être détectés cent fois moins cher en tirant directement sur /mcp et /api/checkout.

Erreur n°2 : se focaliser uniquement sur le temps de réponse moyen.
« Nous avons 500 ms en moyenne, tout est parfait » — et le fait que p95 est à 5 s, on l’oublie. Nous l’avons déjà vu avec les SLO : c’est la queue de distribution (p95/p99) qui détermine l’UX réelle. Sous charge, la moyenne reste souvent correcte, mais la queue augmente de deux à trois fois.

Erreur n°3 : vouloir faire de « l’entreprise‑grade » au lieu d’un smoke‑load pragmatique.
Passer des mois à construire un banc complexe imitant des dizaines de milliers d’utilisateurs, pour une app ChatGPT du niveau de GiftGenius — c’est presque toujours de trop. Il est bien plus utile d’avoir un smoke‑load simple mais régulier à 50–100 VU avec des métriques claires.

Erreur n°4 : scénario de charge irréaliste.
Le script envoie toujours la même requête, sans variation d’utilisateur, de langue, de type de produit, et sans toucher ACP ni les webhooks. Vous testez un happy path brûlant, mais les vrais « angles » du système restent dans l’ombre. Mieux vaut modéliser au moins un parcours simplifié mais crédible : budgets variés, centres d’intérêt différents, une partie des utilisateurs va jusqu’au checkout, une autre non.

Erreur n°5 : vérifier le flux « à l’œil » ou directement en prod.
Le flux est assemblé, déployé en prod, vous voyez des recommandations étranges du modèle et commencez à vous gratter la tête. Un simple script en Zod/JSON Schema aurait pu montrer en une minute que 10 % des produits sont sans images, que 5 % ont un prix de 0, et que 3 % ont la devise XXX. L’absence de validation automatique du flux est l’une des sources les plus fréquentes de gêne dans les apps e‑commerce.

Erreur n°6 : espérer que le LLM « comprendra tout tout seul » avec un flux de mauvaise qualité.
Oui, le modèle sait faire beaucoup, mais il n’inventera pas un prix correct ni la disponibilité. Si le même produit apparaît dans le flux avec des prix différents, ou « en stock »/« hors stock » simultanément, l’agent peut produire des hallucinations et une expérience incohérente. La responsabilité de la propreté des données — c’est la vôtre, pas celle du modèle.

Erreur n°7 : absence de lien entre métriques du flux et SLO généraux.
Vous pouvez avoir un MCP et un ACP parfaitement rapides, mais si 30 % des produits du flux sont « cassés », l’expérience utilisateur restera mauvaise. Souvent, les équipes ne suivent que des SLO techniques (latence, taux d’erreur) et ignorent les SLO sur la qualité des données (pourcentage minimal de SKU valides, maximum de doublons, etc.). Résultat : « les chiffres sont bons », mais « le ressenti est mauvais ».

Erreur n°8 : lancer des tests de charge directement en prod sans préparation.
Quelqu’un décide parfois un vendredi soir de « lancer rapidement k6 sur le MCP de prod », sans prévenir personne. Au mieux, vous brouillerez les métriques réelles et intriguerez l’ingénieur d’astreinte par un pic de trafic ; au pire, vous vous heurterez aux rate limits d’une API externe ou de la solution de paiement. Lancez toujours les premiers scénarios sur staging, et si un test prod est nécessaire — faites‑le de manière maîtrisée, avec créneaux et notifications.

1
Étude/Quiz
Observabilité et qualité, niveau 17, leçon 4
Indisponible
Observabilité et qualité
Observabilité et qualité
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION