Dépannage : trafic
Routes, délais, flux, amonts, gRPC, débit, cache, corps, appel externe et politiques : le symptôme, sa cause et quoi faire.
DépannageExploitationDepuis la version 0.1.0
Sur cette page
Guide d'exploitation : configurer, déployer et observer la passerelle. Ce que fait la fonctionnalité côté produit : guide produit ; l'appeler : guide développeur.
Routage et contrat
| Symptôme | Cause | Action |
|---|---|---|
404 sur une route qu'on croit exposée |
Elle n'est pas dans le contrat. « Servi = déclaré » | L'ajouter au contrat, pas à la configuration |
400 « Query parameter ... is not declared » |
Fermé par défaut : le contrat ne déclare pas ce paramètre | Le déclarer dans le contrat, pas contourner la passerelle |
422 invalid_request |
La requête ne respecte pas le schéma du contrat | L'extension errors nomme le champ et la règle |
| Un en-tête n'arrive pas à l'amont | Il n'est pas déclaré dans le contrat - il est retiré, pas refusé | Le déclarer comme paramètre in: header |
| Refus « segment … has two parameters side by side » ou « a '{' that is never closed » | Un segment de chemin que le routeur ne sait pas lire | Mettre un texte entre les deux paramètres, fermer l'accolade |
| Refus « segments … rank the same and can match the same text » | Deux segments mixtes de même rang lisent le même texte (a{x} et {x}a) |
Rendre l'un plus littéral, ou renommer un chemin |
404 sur /reports/2026.pdf alors que /reports/{year}.pdf est au contrat |
Passerelle antérieure à 1.6.0 : le segment mixte était pris pour un littéral |
Mettre à jour (Servir sa première API) |
Délais, flux et amonts
| Symptôme | Cause | Action |
|---|---|---|
| Un flux arrive d'un coup à la fin | Un intermédiaire bufferise - pas la passerelle | Vérifier l'edge et tout proxy entre le client et elle |
Un flux s'arrête au milieu, journal read budget exhausted |
L'amont s'est tu plus longtemps que server.timeouts.read |
Faire émettre un battement (: keepalive) à l'amont, ou relever read |
504 upstream_timeout |
L'amont n'a pas répondu dans le budget de l'opération | Lire flexway_upstream_duration_seconds ; relever x-flexway-timeout sur cette opération, pas le défaut global |
504 upstream_timeout « budget was spent before its upstream could be called » |
Un external-call de la phase requête a consommé tout le budget de l'opération |
Raccourcir son timeout, ou relever x-flexway-timeout de l'opération |
503 upstream_unavailable avec Retry-After |
L'amont refuse les connexions : il est arrêté | Vérifier l'amont ; la passerelle a déjà repris une fois si la méthode le permettait |
502 upstream_error |
L'amont a répondu quelque chose qui n'est pas du HTTP exploitable | Chercher côté amont, pas côté passerelle |
503 avec Flexway-Degraded: circuit-open |
L'amont échoue ; le coupe-circuit répond à sa place | Réparer l'amont ; un appel d'essai passe après cooldown |
503 avec Flexway-Degraded: upstream-saturated |
max_in_flight atteint sur cet amont |
Relever le plafond, ou trouver pourquoi l'amont ralentit |
503 overloaded avec Flexway-Degraded: shedding, flexway_shed_total{reason="in_flight"} qui monte |
La réplique est à son plafond de requêtes en vol (server.in_flight, dérivé de sa limite mémoire s'il n'est pas écrit) : elle refuse l'excédent au lieu d'être tuée (OOM) |
Ajouter des répliques, ou plus de CPU et de mémoire à chacune ; la limite en vigueur est dans /config (server.in_flight) et au journal de démarrage |
gRPC
| Symptôme | Cause | Action |
|---|---|---|
| Refus au chargement « google.api.http ... not supported at this version » | Variable sur plusieurs segments, joker ou verbe dans une règle REST | Une variable par segment (/v1/shelves/{shelf}/books/{book}), ou la méthode en gRPC seulement |
| Refus au chargement « is a gRPC method and relays to upstream » | La méthode tombe sur un amont HTTP (le default) |
Nommer son amont dans flexway.v1.operation.upstream, déclaré protocol: grpc |
Client gRPC : UNIMPLEMENTED |
La méthode n'est pas dans le jeu servi - jeu périmé | Reconstruire le .binpb : il est relu sans redémarrage |
REST : upstream_status |
L'amont gRPC a répondu une erreur : c'est sa réponse, pas un échec de la passerelle | Lire grpc.status et grpc.details du problème |
Débit et quotas
| Symptôme | Cause | Action |
|---|---|---|
429 rate_limited |
Le seau de l'appelant est vide | Lire Retry-After ; relever rps/burst de la classe, ou changer la classe de l'opération |
| Tous les anonymes semblent partager un seau | La passerelle voit l'adresse du bord - ou, derrière un load balancer cloud sans proxy protocol, celle du load balancer - pas celle du client | Déclarer le bord dans server.trusted_proxies ; lire x-forwarded-for dans le journal d'accès du bord, et activer le proxy protocol au load balancer et au bord (Poser des quotas du guide) |
Cache de réponses
| Symptôme | Cause | Action |
|---|---|---|
Flexway-Cache: miss à chaque requête |
L'amont interdit de garder (no-store, no-cache, private, Set-Cookie), répond sans Content-Length, au-delà de server.cache.max_entry_bytes, ou avec un statut autre que 200, 203, 204, 301, 404 |
Lire les en-têtes de la réponse de l'amont ; flexway_cache_lookups_total par opération |
Aucun Flexway-Cache sur une opération cachée |
Contournement : appelant identifié sur un cache public, condition when fausse, méthode autre que GET/HEAD |
result="bypass" dans flexway_cache_lookups_total ; un cache par appelant se déclare scope: subject à l'opération |
Démarrage refusé : response cache declaration(s) refused |
Un cache sur un flux, un WebSocket, gRPC, l'inférence, une écriture, ou public sur une opération authentifiée | Le message nomme l'opération et la porte (x-flexway-cache ou la politique) |
Corps et statut de réponse
| Symptôme | Cause | Action |
|---|---|---|
502 response_too_large |
Une opération à politique de corps a reçu une réponse au-delà de server.body.max_bytes |
Relever server.body.max_bytes (rechargeable), ou paginer côté amont |
502 upstream_error sur une opération transformée, journal an upstream answer could not be transformed |
L'amont a répondu autre chose que du JSON lisible, compressé malgré Accept-Encoding: identity, ou sans un champ projeté avec on_missing: fail |
Le journal nomme la cause et le champ ; corriger l'amont, ou passer à on_missing: omit |
Démarrage refusé : body policy attachment(s) refused |
Une politique de corps atteint un flux, une réponse non JSON, gRPC ou l'inférence ; ou elle retire un champ requis, garde un champ non déclaré, masque avec un type refusé | Le message nomme l'opération et la politique ; l'attacher plus étroitement ou !nom |
flexway_policy_nonconformant_total monte |
Un corps servi ne tient plus le schéma de son statut (échantillon) - l'amont a changé, ou le statut n'est pas déclaré | Le journal departs from its schema donne le champ et le mot-clé ; la réponse est servie quand même |
Refus au chargement « body is read by the conditions of transform-body, redact and map-status only » |
Une autre politique lit body dans sa condition ou un gabarit |
Lire le corps dans une politique de corps, ou s'en passer |
Appel externe
| Symptôme | Cause | Action |
|---|---|---|
403 (ou autre 4xx) avec le code d'une politique external-call |
Le service externe a refusé : deny.when vaut vrai sur sa réponse |
Attendu ; le motif est chez le service, jamais recopié dans le problème |
504, 503 ou 502 sans que l'amont soit appelé, journal external call failed_closed |
Le service externe n'a pas répondu à temps, est injoignable, a son circuit ouvert ou a rendu une réponse illisible pour deny.when / set_headers - et la politique est fail-closed |
Le journal donne la politique et la cause ; flexway_policy_external_calls_total{outcome="failed_closed"} ; réparer le service, ou fail-open si la décision peut manquer |
Un en-tête attendu d'un external-call manque, journal external call en WARN |
fail-open a absorbé une panne du service |
flexway_policy_external_calls_total{outcome="failed_open"} ; le journal donne la cause |
Démarrage refusé : external-call attachment(s) refused |
timeout au-delà du budget d'une opération, send.body sur un flux, phase response sur un WebSocket, gRPC ou l'inférence |
Le message nomme l'opération et la politique |
Politiques
| Symptôme | Cause | Action |
|---|---|---|
| Refus au démarrage « is protected - the gateway alone writes it » | Une politique écrit un en-tête que seule la passerelle pose (identité, trace, tenant, X-Forwarded-*) |
Choisir un autre nom d'en-tête |
L'amont reçoit X-User-Roles: [seller admin] |
Passerelle antérieure à 1.6.0 : une liste rendue à la manière de Go |
Mettre à jour : une liste arrive seller,admin ; {{ auth.claims.roles.join(' ') }} pour un autre séparateur (Enrichir un flux) |
Refus au démarrage undeclared reference to 'x' ou found no matching overload dans une valeur |
Une fonction que le langage n'a pas, ou join sur un séparateur qui n'est pas du texte |
Seules les fonctions de CEL et join existent ; corriger l'expression |
| Refus au démarrage « on_missing is required » | Une valeur est une expression {{ … }} sans dire quoi faire si elle manque |
Ajouter on_missing: skip, empty ou fail |
| Refus au démarrage « two … policies at the same level » | Deux cors (ou rate-limit, rewrite-path) au même niveau |
En garder une, ou déplacer l'autre vers un niveau plus précis |
500 internal_error, journal a policy value is missing |
on_missing: fail et la valeur manque pour cet appelant |
Ajouter une condition when, ou passer à skip |
| Une politique n'agit pas | Le journal de démarrage dit NOT applied : son type vient d'une version ultérieure |
Lire effective_chains dans /config |