Contexte et architecture du cache de fichiers
Le service de distribution de paquets de PyPI repose sur files.pythonhosted.org, un CDN Fastly placé devant trois back‑ends. Lorsqu’un fichier est publié, il est d’abord stocké dans Amazon S3 (classe Glacier Instant Retrieval) puis répliqué vers Backblaze B2 grâce à un accord d’« egress‑free ». Fastly interroge d’abord B2 ; en cas d’absence de réponse ou d’erreur, il bascule vers S3. Une fois le fichier mis en cache, le Cache‑Control indique max‑age=365000000, immutable, public, soit une durée de vie théorique de 11,5 ans. Un troisième back‑end, Conveyor, gère les requêtes non‑packagées et les redirections legacy.
flowchart TD
Client([Client request]) --> Edge{Fastly edge}
Edge -->|package file| B2[(B2: egress-free cache)]
Edge -->|everything else| Conveyor[Conveyor]
B2 -->|200 or 206| Response([Response to client])
B2 -.->|404, timeout, or 5xx| Archive[(S3: origin, fallback)]
Archive --> Response
Conveyor --> Response
Défaillance du canary Fastly et impact client
Entre le 15 et le 28 août 2026, les utilisateurs ont rencontré plus de 88 réponses HTTP 502 en six heures, affectant 32 paquets différents. L’enquête a isolé le problème à un seul nœud de cache de Seattle (identifié par l’en‑tête x‑served‑by). Fastly avait déployé un canary – un sous‑ensemble de son réseau testant une nouvelle configuration de routage – dont le rollback partiel a laissé la configuration de cache inchangée alors que la couche de routage était déjà mise à jour. Cette incohérence a fait renvoyer systématiquement des 502 à tout le trafic dirigé vers ce point de présence (POP).
Le correctif côté Fastly, appliqué le 28 août, a retiré le trafic du PSF du cohort canary et a restauré la cohérence configuration‑routage. Depuis, les métriques de Datadog montrent un taux d’erreur nul et les téléchargements sont revenus à la normale.
Bugs internes de configuration PyPI et correctifs appliqués
Parallèlement, deux défauts dans la configuration Fastly de PyPI ont été découverts. Le premier, corrigé par infra#237, concernait le mécanisme de bascule vers S3 : Fastly ne déclenchait la requête d’archive que si B2 renvoyait un code d’erreur, mais ignorait les timeout ou échecs TLS, générant ainsi des 503 synthétiques. Le deuxième, lié à la segmented caching, ne supportait pas les requêtes de type suffixe (bytes=-1024) ou les plages dépassant la fin du fichier, renvoyant un 501 « Not Implemented ». Certains installateurs utilisent ces plages pour lire les métadonnées PEP 658 sans télécharger le fichier complet, ce qui provoquait des échecs jusqu’à l’exemption introduite par infra#241 et infra#243.
Leçons et perspectives d’amélioration
Cette série d’incidents montre la sensibilité d’une chaîne de distribution à deux niveaux : la synchronisation des configurations lors d’un déploiement canary et la robustesse des chemins de secours internes. La dépendance à un seul POP pour le trafic canary a créé un point de défaillance unique, soulignant l’importance de tests de réversibilité automatisés. Du côté de PyPI, la prise en compte explicite des timeout B2 et la prise en charge complète des syntaxes HTTP Range renforcent la résilience du service. À l’avenir, PyPI prévoit de réintégrer le programme canary uniquement après la mise en place de notifications de changement de configuration et de contrôles de cohérence entre routage et cache, afin de limiter l’exposition à des désalignements similaires.