Le job d’export est vert, le journal indique HTTP 200, pourtant le document attendu n’apparaît pas dans le traitement partenaire. Sur Amazon S3, le risque est de clôturer la livraison sur les en-têtes avant de lire le résultat multipart complet. Le service peut commencer une réponse de succès, puis signaler une erreur dans son corps. Contrairement à ce que laisse penser le statut 200, cette tentative peut donc avoir échoué : le connecteur laisse alors la gestion attendre un fichier non finalisé.
Le scénario fictif EXP-309 suit une extraction CSV transmise en deux parties. Il sert à examiner trois décisions précises : interpréter la réponse de finalisation, conserver les reçus des parties réellement envoyées et décider quelle tentative peut être reprise. Recalculer l’export ou récupérer une liste distante ne suffit pas à reconstruire ces décisions. L’identité de l’envoi et la version du fichier doivent rester liées jusqu’au résultat examiné par le destinataire.
Nous avons exécuté un exercice original avec Botocore 1.43.114 : 72 contrôles observent quinze échanges à réponses préparées, sans connexion à AWS. Le véritable client prépare les requêtes, décode le XML et traite les erreurs. Ce laboratoire révèle ce que fait le SDK installé ; il ne prouve ni la conservation d’octets dans S3, ni les autorisations d’un compte, ni la validation d’un import ERP. Le jeu de données est entièrement fictif.
Notre prestation d’intégration AWS pour les échanges de fichiers métier peut partir de cette frontière entre transfert et finalisation. Dans un projet d’intégration API entre ERP et applications partenaires, nous recherchons l’opération qui manque réellement à la livraison. Vous allez voir quelles preuves conserver, quels refus interdisent un simple retry et pourquoi le compteur de parties transférées ne doit pas fermer le dossier documentaire.
Pour qui : un export volumineux dont la finalisation reste incertaine
Retrouver le client qui transforme la réponse S3 en statut métier
Le cas concerne une application qui utilise les opérations multipart de S3 pour déposer un fichier : préparation d’un envoi, transfert de parties, puis demande de composition. Cela peut être un export ERP, un document volumineux remis à un partenaire ou un fichier produit par un traitement asynchrone. Il faut identifier le composant qui décide « document disponible » : un client officiel, un adaptateur HTTP, un navigateur ou une passerelle qui résume la réponse.
Cette précision évite un mauvais correctif. Si un SDK officiel lève déjà une exception mais que l’adaptateur la remplace par un statut vert, modifier le découpage du fichier ne résoudra rien. Si le connecteur lit seulement les en-têtes d’une réponse HTTP, la perte d’information se situe plus tôt. Le diagnostic commence donc à l’endroit où le résultat natif devient une décision de clôture, avec la version du client et sa configuration de retry.
Séparer l’objet absent, l’ancien objet et le fichier refusé en aval
Un objet introuvable après finalisation n’est pas le même incident qu’un objet existant dont le contenu est ancien. Un fichier présent mais rejeté par le lecteur CSV ouvre encore un autre dossier. EXP-309 vise une nouvelle clé d’objet, avec une création conditionnelle ; il ne propose pas une méthode générale pour remplacer un document déjà publié. Si votre traitement écrase toujours le même nom, la politique de version et les producteurs concurrents doivent être qualifiés avant toute reprise.
Le coût caché apparaît quand le service métier demande plusieurs régénérations pour compenser une livraison qu’il ne sait pas retrouver. Les équipes manipulent alors des fichiers portant le même nom, avec des dates et des contenus différents. Le support doit pouvoir dire quelle extraction était attendue et quelle tentative lui correspond. Une nouvelle extraction peut être légitime, mais elle doit recevoir sa propre identité plutôt que réparer silencieusement l’histoire de la précédente.
Lire le résultat de CompleteMultipartUpload jusqu’au bout
Ne pas clôturer sur les seuls en-têtes de succès
La référence officielle de CompleteMultipartUpload décrit une réponse qui peut commencer en HTTP 200 pendant le traitement, puis contenir une erreur. Un client HTTP direct doit donc examiner le corps reçu complètement. Une métrique qui compte seulement les statuts 2xx peut annoncer un succès alors que l’opération n’a pas livré l’objet attendu. Le problème ne se règle pas en renommant cette métrique « succès métier ».
Dans notre réponse préparée, le corps contient un élément Error portant le code InternalError. Botocore 1.43.114 le reconnaît dans son traitement S3 et produit une exception dont les métadonnées indiquent un statut reclassé à 500. Le témoin conserve aussi le statut 200 fourni à l’entrée. Ces deux observations ne se contredisent pas : elles correspondent à la réponse préparée et à son interprétation par le client. Aucun serveur AWS n’a émis cette erreur pendant l’expérience.
Tracer l’exception sans masquer les relances du SDK
Les clients officiels peuvent traiter ces erreurs et appliquer leur politique de nouvelle tentative. Le témoin fixe le nombre total d’essais à un pour rendre chaque échange visible : il observe zéro retry implicite. Ce réglage sert au laboratoire, pas à recommander la suppression des relances en production. Votre diagnostic doit relever les paramètres effectifs, car une seule invocation applicative peut autrement représenter plusieurs requêtes vers le service.
La journalisation rapproche l’export EXP-309, l’UploadId concerné, l’opération, l’exception décodée et les tentatives autorisées. Une passerelle qui conserve uniquement la durée et le premier statut HTTP perd le signal nécessaire au support. Le monitoring doit distinguer un transfert accepté d’une composition confirmée. Le seuil d’alerte, convenu avec le destinataire, porte sur le temps entre le dernier reçu de partie et la finalisation confirmée. Un dépassement ouvre l’investigation du dossier ; il ne déclenche pas une nouvelle extraction. Ce signal faible reste utile même lorsque les graphiques de disponibilité demeurent verts.
Construire la demande finale avec les reçus du producteur
Conserver UploadId, PartNumber et ETag sans les réinventer
La vue d’ensemble du multipart S3 demande de conserver sa propre liste des numéros de parties et des ETag retournés pour préparer la finalisation. Cette liste appartient à une tentative identifiée par son UploadId. Notre proposition lui associe également la révision d’extraction et une empreinte locale du fichier source. Ces informations ont des fonctions différentes : la référence d’envoi désigne le transfert, tandis que la révision et l’empreinte rattachent ce transfert aux octets attendus.
Le témoin transmet 5 400 019 octets, découpés en une première partie de 5 242 880 octets et une dernière de 157 139 octets. La première respecte la taille minimale retenue pour cette configuration de bucket généraliste ; la dernière constitue la fin du fichier. Ce petit fichier sert à l’essai, sans fixer le seuil de passage au multipart de votre application. Le SDK renvoie les ETag fournis par nos réponses préparées. Nous les gardons comme des valeurs opaques : le mapping ne retire pas leurs guillemets et ne les remplace pas par une empreinte calculée sur la source.
La référence UploadPart précise qu’un nouvel envoi utilisant le même numéro remplace la partie précédente pour cet upload. Un reçu ne peut donc pas être conservé indéfiniment comme si ce numéro désignait toujours les mêmes octets. Le producteur doit lier le reçu à la tentative qui a accepté sa tranche. La demande finale du laboratoire reprend les deux reçus, triés par numéro, sans confondre cet ordre avec celui dans lequel le support les a retrouvés. Le payload XML de cette API REST contient les numéros de parties et les ETag que notre client soumet à la composition. Le fragment suivant reformate ce XML réellement observé.
<CompleteMultipartUpload xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Part>
<PartNumber>1</PartNumber>
<ETag>"opaque-part-one"</ETag>
</Part>
<Part>
<PartNumber>2</PartNumber>
<ETag>"opaque-part-two"</ETag>
</Part>
</CompleteMultipartUpload>
Utiliser ListParts comme contrôle, pas comme plan de livraison
La pagination de ListParts doit être parcourue jusqu’à sa fin. Notre jeu d’essai force deux pages et vérifie que le marqueur natif de continuation passe dans la requête suivante. Le programme refuse une page tronquée qui n’offre pas de marqueur exploitable. Une première page rassurante ne permet pas de conclure qu’un envoi est complet ; il faut connaître la fin de la collection avant de rapprocher les parties du dossier source.
La règle locale proposée exige la même liste de numéros, de tailles et d’ETag que les reçus conservés. Elle bloque une partie absente, une partie étrangère et un ETag différent. Ce rapprochement ne transforme pas l’inventaire en preuve d’identité du fichier : une liste distante ne restitue ni l’intention du producteur ni sa révision d’export. Sans les reçus initiaux, la reprise doit traiter cette perte de preuve plutôt que fabriquer une composition à partir de tout ce qu’elle trouve.
Qualifier séparément le checksum et l’identité de la livraison
L’ETag d’un objet multipart ne doit pas être présenté comme son empreinte MD5 complète. Le contrôle d’intégrité documenté par AWS distingue notamment les checksums portant sur l’objet complet et les checksums composites. L’algorithme, le type et les champs fournis doivent correspondre au mode retenu. Comparer deux chaînes qui utilisent des conventions différentes peut créer une fausse alerte, ou donner une assurance injustifiée sur le fichier remis au partenaire.
Dans EXP-309, l’empreinte SHA-256 répond à une question locale : avons-nous encore les mêmes octets source avant de construire la demande ? Elle ne répond pas à la question distante : quels octets S3 a-t-il effectivement conservés ? La recette doit ajouter le mécanisme d’intégrité choisi et la lecture nécessaire à la livraison réelle. Même un fichier intègre peut appartenir à la mauvaise extraction ; la référence métier et la révision restent donc nécessaires à côté du contrôle des octets.
Exercice : suivre quinze requêtes préparées par Botocore
Observer le vrai client avant tout accès réseau
Le programme complet de finalisation multipart utilise Botocore 1.43.114 sous Python 3.14.8. Des gestionnaires d’événements before-send.s3 retournent les réponses préparées avant l’appel au transport HTTP. Le sérialiseur, le parseur et les gestionnaires d’erreurs S3 restent ceux du paquet installé. Il s’agit de quinze passages par ces événements, pas de quinze connexions ni d’un service S3 simulé avec sa persistance.
python3 -m venv .venv-s3
.venv-s3/bin/python -m pip install botocore==1.43.114
.venv-s3/bin/python -B multipart_completion_receipts.py
# checks_passed: 72
# prepared_before_send_invocations: 15
# real_http_requests: 0
# connection_attempts: 0
L’installation depuis le registre demande un accès réseau distinct. Pendant l’essai, les appels HTTP réels et les connexions instrumentées sont bloqués. Le client emploie une adresse .invalid et ne signe pas les requêtes. Le calcul automatique des checksums facultatifs est désactivé pour isoler l’observation ; l’empreinte SHA-256 de la source sert uniquement de liaison locale. Le programme ne démontre aucune vérification de checksum effectuée par AWS.
Lire les contre-exemples autant que la réponse acceptée
Les quinze échanges couvrent la création d’un upload, deux transferts, deux pages d’inventaire, une finalisation en erreur, une réponse de succès distinctement préparée et une lecture de propriétés. Trois finalisations refusées et quatre lectures d’inventaires anormaux complètent l’ensemble. Le succès fourni après l’erreur ne prouve pas qu’AWS accepterait une relance dans cette situation : le laboratoire fournit ces réponses séparément pour examiner le comportement du client, sans moteur de stockage entre les appels.
| Cas du laboratoire | Observation obtenue |
|---|---|
| HTTP 200 contenant Error | Exception InternalError, statut client reclassé |
| Inventaire réparti sur deux pages | Marqueur repris dans la seconde requête |
| Reçus présentés dans l’ordre inverse | Parties soumises dans l’ordre numérique |
| ETag distant différent | Aucune demande finale supplémentaire |
| Source modifiée à taille égale | Reprise refusée avant requête |
| Succès technique préparé | Aucune référence ERP publiée |
Le programme compare aussi un fragment source à une substitution de même taille. Il montre pourquoi un contrôle de métadonnées n’observe pas les octets stockés à distance. De même, la réponse HEAD préparée permet de vérifier le décodage de la taille et de l’ETag, sans lire les lignes du CSV. Le seuil du témoin est explicite : zéro référence documentaire écrite dans l’état ERP fictif. L’acceptation fonctionnelle du fichier reste une étape à tester avec son véritable destinataire.
Erreurs fréquentes : appliquer le même retry à des refus différents
Examiner InvalidPart avant de renvoyer la même composition
La réponse préparée InvalidPart est conservée avec son statut 400. Le témoin ne l’assimile pas à une panne temporaire. Dans une investigation réelle, on rapproche l’UploadId, les reçus et les parties encore disponibles avant de soumettre une correction. Changer le numéro d’une partie ou recopier son ETag depuis une autre tentative n’est pas une réparation neutre : cela modifie le contenu de la demande qui doit produire le document.
Le contexte source doit être relu au même moment. Le contrôle local refuse une révision différente et un contenu de même taille dont l’empreinte a changé. Cela traite, par exemple, un job qui retrouve le chemin du CSV, alors que ce chemin contient désormais l’extraction suivante. Si les octets d’origine n’existent plus, la décision porte sur une nouvelle livraison à identifier. Elle ne consiste pas à continuer un upload ancien avec les parties d’un nouveau fichier.
Distinguer conflit de création et précondition refusée
Notre client envoie If-None-Match: * sur la finalisation d’une nouvelle clé. Les réponses préparées 409 ConditionalRequestConflict et 412 PreconditionFailed produisent deux exceptions distinctes. Le programme prouve leur décodage et la présence de l’en-tête, sans tester son application par S3. La procédure native de conflit conditionnel impose de réinitialiser l’envoi multipart et de retransmettre les parties après ce 409 ; elle ne se résume pas à répéter indéfiniment la même requête finale.
Une précondition refusée doit aussi faire examiner l’objet déjà présent et l’intention de création. Retirer l’en-tête pour faire passer le job pourrait transformer une création protégée en remplacement. Le runbook doit réserver cette décision à un responsable autorisé, avec une vérification du document qui existe et du dossier qui l’a publié. Le second signal faible est précisément une hausse de ces refus sur une clé supposée unique : elle peut révéler une collision de producteurs ou une politique de nommage devenue ambiguë.
La recette connectée exige aussi la signature AWS Signature Version 4 prévue pour ces écritures conditionnelles ; le client non signé du laboratoire ne la teste pas. Dans un bucket versionné, la condition porte sur la version courante, avec le cas particulier d’un marqueur de suppression. Enfin, un upload multipart en cours ne réserve pas à lui seul la clé contre un autre producteur. L’UploadId permet de suivre une tentative ; la politique de création décide comment cette tentative peut publier son objet.
Plan d’action : reprendre EXP-309 sans inventer son historique
Constituer le dossier de reprise avant de changer le connecteur
Le responsable de l’extraction retrouve la révision et les octets attendus. L’équipe AWS qualifie le bucket, la clé, l’identité technique et les opérations autorisées. L’intégrateur rapproche les reçus de transfert et le résultat de finalisation ; le destinataire précise ce qui autorise réellement l’import. Lorsque l’ERP est maintenu par un autre prestataire, Dawap coordonne cette investigation avec lui pour éviter qu’une régénération fonctionnelle soit confondue avec une réparation du transfert.
- Retrouver l’export demandé, sa révision et l’UploadId de la tentative à examiner.
- Contrôler le corps complet de finalisation, l’exception du client et les retries effectifs.
- Rapprocher les reçus du producteur avec toutes les pages de parties disponibles.
- Décider correction, nouvel envoi ou investigation de conflit selon le refus natif observé.
- Vérifier l’objet publié et sa prise en charge avant de diffuser sa référence documentaire.
La première recette provoque une erreur dans un HTTP 200, puis une perte de reçu et un changement de source entre deux tentatives. Les seuils d’admission viennent de ces cas : aucune finalisation construite depuis un inventaire incomplet, aucune reprise d’un upload attribué à une autre extraction et aucune clôture ERP sur un simple accusé HTTP. La recette connectée ajoute les producteurs concurrents, le timeout après traitement et le redémarrage du composant qui conserve les reçus. Le timeout laisse le résultat incertain : il faut retrouver la tentative avant de décider de la retransmission.
Faire durer les preuves et fermer les envois abandonnés
Dans le programme, source, reçus et décisions restent en mémoire. En production, leur persistance doit survivre au crash du job. Le contrat de reprise indique ce qui est enregistré avant et après chaque transfert, comment retrouver une tentative incertaine et où s’applique l’idempotence du traitement applicatif. Un rollback du connecteur doit pouvoir relire ces preuves ; il ne suffit pas de redéployer l’ancienne version si son format de reçus ne comprend plus les dossiers ouverts.
Les parties non finalisées ont aussi un coût de stockage à suivre. La procédure d’abandon d’un upload multipart doit tenir compte des transferts encore en cours ; leur arrêt n’est pas démontré par le seul envoi d’un abandon. Une politique de cycle de vie peut compléter ce nettoyage, avec son propre délai configuré. Le renouvellement d’un accès ou la relance d’un job ne remplace pas une décision explicite sur les envois devenus inutiles.
Les contrats restent propres à chaque fournisseur. La validation des blocs d’un export Azure Blob mobilise une liste et des règles de sélection différentes. La reprise d’un dépôt Google Drive après perte de réponse traite une autre identité de fichier. Ces comparaisons servent à choisir l’investigation adaptée, sans plaquer l’UploadId de S3 sur tous les échanges documentaires.
Conclusion : la finalisation doit porter un résultat interprété
EXP-309 rappelle une limite concrète d’un suivi fondé sur le statut HTTP : une réponse peut commencer par 200 sans aboutir à la finalisation attendue. Le client doit conserver son interprétation complète, tandis que les reçus relient la composition aux parties de la bonne extraction. Les 72 contrôles du laboratoire rendent ces frontières observables ; ils laissent à la recette AWS les preuves qui dépendent des droits, du stockage et des producteurs réels.
Avec notre accompagnement en intégration AWS reliée aux processus documentaires, un pilote peut cibler une extraction et un refus de finalisation réellement rencontrés. Nous examinons le client installé, les reçus conservés et la décision prise après l’exception, afin de corriger l’étape qui empêche le document d’être livré.
Dawap peut ensuite cadrer l’intégration API de cet export avec votre ERP et son destinataire. Le résultat recherché est un dossier que le support sait reprendre : une extraction connue, une tentative identifiable et une preuve de prise en charge à retrouver. L’extension à d’autres fichiers vient après cette recette, avec les responsabilités de reprise et le format des reçus explicités.