Trois réalisations détaillées de bout en bout : contexte, contraintes, diagnostic, décisions, résultats mesurés, et ce que j’en ai retiré. Le but n’est pas d’exposer une stack, mais de montrer un raisonnement.


Optimisation de la base de données — AWS RDS / MariaDB Link to heading

Contexte Link to heading

Plateforme média multi-supports (65 radios, 460 000 sessions mensuelles) reposant sur une base MariaDB hébergée sur AWS RDS (db.m7i.xlarge — 4 vCPU, 16 Go), sollicitée par l’ensemble des services : site public, back-office éditorial et API custom (Drupal), application mobile. Le schéma imposé par Drupal est non trivial et loin d’être optimal — une contrainte du socle, pas un choix de l’équipe. Avril 2026, 3 semaines au total.

Enjeux Link to heading

150 journalistes dépendent du back-office : chaque saturation bloque la production éditoriale. Le site public et l’application mobile reposent sur la même base — les lenteurs touchent aussi les auditeurs. La charge augmentait dans le temps : sans action, les saturations allaient devenir la norme.

Contraintes Link to heading

Aucune interruption de service acceptable. Équipe de 3 développeurs : impossible de mobiliser quelqu’un à plein temps. L’upscale de l’instance a été écarté d’emblée — trop cher, et l’instance était déjà surdimensionnée par rapport à sa charge nominale. Monter en gamme aurait traité le symptôme, pas la cause.

Diagnostic Link to heading

Symptômes : 3 à 4 pics de charge par semaine, imprévisibles, atteignant 400 AAS (Average Active Sessions) sur 4 vCPU — environ 100 fois la capacité de traitement simultané ; CPU à 100 %, 30 à 90 minutes par épisode ; erreurs 500 et 504.

Deux sources de charge distinctes : le rebuild du cache Drupal (déclenché par les déploiements et de rares actions éditoriales), corrélé instantanément aux pics ; et certaines requêtes coûteuses indépendantes, identifiées dans le Top SQL.

Investigation Link to heading

Outils : RDS Performance Insights (classement Top SQL) et CloudWatch (CPU, AAS). Démarche : corrélation entre événements déclencheurs et pics, collecte des requêtes les plus coûteuses pendant et hors pics, analyse des patterns d’accès.

L’investigation a été accélérée par un LLM (Claude), sous cadre strict : éléments fournis (code concerné, Top SQL, contexte système) ; workflow imposé (analyse → hypothèses → critique des solutions → validation humaine → rapport → lots priorisés → exécution suivie par statut). Le LLM a accéléré l’analyse et structuré l’exécution ; la validation des solutions et les arbitrages sont restés humains.

Décisions Link to heading

Index ciblés sur les attributs désignés par l’analyse plutôt que posés au hasard ; réécriture des requêtes les plus coûteuses ; correction des patterns d’accès aux données. Travaux menés par lots priorisés (importance × compatibilité), avec mesure avant/après à chaque lot, sans interruption de service.

Résultats Link to heading

Mesure sur un mois avant / un mois après :

  • charge CPU RDS réduite de 54 % ;
  • disparition de la principale source de saturation — plus de pics à 100 % de CPU ;
  • pics résiduels à 50 AAS (contre 400), beaucoup moins fréquents ;
  • forte baisse des erreurs 500/504 sur le back-office.

La baisse de charge rend désormais possible un downsizing de l’instance — analyse de dimensionnement en cours. La réduction de coût n’est pas encore réalisée.

Ce que j’en retiens Link to heading

Les gains significatifs viennent rarement de micro-optimisations : ils viennent de la compréhension du système dans son ensemble. Le réflexe « upscaler » aurait coûté cher sans rien résoudre — comprendre avant de dépenser. Un schéma imposé par un CMS n’interdit pas les gains majeurs, à condition que l’analyse désigne précisément où agir.


Passerelle d’intégration entre prestataires — AWS serverless Link to heading

Contexte Link to heading

La plateforme s’appuie sur deux prestataires externes : un tunnel de don (collecte en ligne) et un CRM (gestion des donateurs). Aucune intégration native, et les deux prestataires étaient incapables de faire communiquer leurs systèmes. Conception et développement seul, novembre — décembre 2025.

Enjeux Link to heading

Les dons représentent plus de 50 % du financement de la radio. Chaque don devait arriver dans le CRM ; sans intégration, saisie manuelle ou données perdues. Fiabilité non négociable : un don perdu est inacceptable, un don compté deux fois aussi. Charge en pics : 2 à 3 campagnes par an, dont une grande campagne de fin d’année pesant à elle seule ~50 % de la collecte.

Contraintes Link to heading

Aucun contrôle sur les deux systèmes : formats d’entrée et de sortie imposés. Campagne imminente. Coût de fonctionnement le plus bas possible.

Choix de l’architecture Link to heading

Le tunnel de don émet un webhook à chaque don : pas de polling nécessaire, l’architecture peut être entièrement événementielle. Serverless sur AWS pour trois raisons :

  • stack déjà maîtrisée — l’infrastructure de la plateforme est sur AWS, aucun nouvel écosystème à opérer ;
  • coût aligné sur l’usage — la charge arrive par pics ; un serveur permanent serait payé à ne rien faire la majorité de l’année ;
  • briques managées — secrets, files d’attente, rejeu fournis par la plateforme plutôt que codés et maintenus à la main.

Décisions Link to heading

Passerelle serverless décrite en infrastructure as code (CDK) :

Brique Rôle
API Gateway point d’entrée du webhook
Lambda transformation du format A vers le format B
DynamoDB unicité — déduplication par identifiant de transaction
SQS découplage et rejeu : 3 tentatives avant dead-letter
Secrets Manager tokens des deux prestataires
IAM permissions dédiées, minimales
Dead-letter queue file sans rejeu → alerte e-mail → traitement manuel

Gestion des erreurs à deux niveaux : transitoires → rejeu automatique (SQS, 3 tentatives) ; structurelles (ex. attribut rejeté par l’API du CRM, où le rejeu ne changerait rien) → dead-letter, alerte e-mail, traitement manuel par le support.

Implémentation Link to heading

Développement en environ deux mois, seul, en parallèle de l’activité courante. Mise en service progressive : envoi par lots pour tester la charge et valider le comportement, puis bascule en flux continu.

Résultats Link to heading

  • en production depuis début 2026 ;
  • ~10 000 dons traités, aucun incident ;
  • aucun doublon — unicité garantie par conception (identifiant de transaction dans DynamoDB) ;
  • aucun don perdu — les échecs partent en dead-letter et sont traités manuellement ;
  • coût de fonctionnement : 4 € par mois, pour un flux qui porte plus de 50 % du financement.

Ce que j’en retiens Link to heading

Concevoir pour la défaillance (files, rejeu, dead-letter, alertes) coûte peu au départ et transforme les erreurs en tickets de support plutôt qu’en incidents de production. Entre deux systèmes qu’on ne contrôle pas, on ne maîtrise que deux choses : le contrat de données et l’idempotence — l’identifiant de transaction comme clé d’unicité rend les doublons impossibles par conception. Le serverless est pertinent quand la charge arrive par pics.


Migration de données lors de la fusion (2025) Link to heading

Contexte Link to heading

En 2025, l’union de radios a fusionné avec une autre radio disposant de sa propre plateforme (site, back-office, données éditoriales, médias). Objectif : servir l’ensemble des radios depuis une seule plateforme — la nôtre — et décommissionner celle de la radio entrante. Projet piloté et réalisé seul, en fil rouge sur 6 mois, deadline fixée par la direction.

Enjeux Link to heading

Continuité éditoriale : la radio entrante devait continuer à publier pendant la migration. Une dizaine de journalistes à intégrer au back-office. Des centaines de Go de médias à rapatrier.

Contraintes Link to heading

Aucun export exploitable côté source : les données n’étaient accessibles que via l’API de leur plateforme. Modèles de données incompatibles. Médias à mettre aux standards internes. Projet mené seul, sans arrêt de l’activité courante.

Diagnostic Link to heading

Périmètre arbitré avec la direction et la rédaction : migrer l’historique des deux dernières années (4 000 épisodes, 1 500 articles, avec leurs médias) — tout l’historique n’avait pas la même valeur éditoriale, et chaque année supplémentaire aurait allongé la migration sans bénéfice proportionnel. Chaîne décomposée en quatre étapes : extraire (API source) → transformer (mapping A → B) → rapatrier les médias → charger.

Décisions Link to heading

  • Extraction : parcours complet de l’API source en Python, avec pagination et retry sur erreurs réseau.
  • Transformation : scripts Python produisant un format pivot JSON ; mapping scrupuleux (dates, catégories, liens avec l’existant). Rattachement à la taxonomie « radios » qui, via le contrôle d’accès du back-office, donne automatiquement les bons droits aux journalistes entrants — aucune gestion de permissions manuelle.
  • Médias : plusieurs centaines de Go (audio, images) rapatriés et stockés sur S3, mis aux standards internes (dimensions, renommage).
  • Chargement : import via le module Drupal Feeds existant plutôt qu’un importeur sur mesure — moins de code à écrire et à maintenir, et passage par le chemin d’entrée officiel du CMS (validations et hooks inclus).
  • Stratégie : migration par lots (import → test → validation → lot suivant), validée par moi et par les métiers sur un critère simple de similitude source/cible ; rejeu idempotent — un lot peut être rejoué sans risque.

Résultats Link to heading

  • historique de deux ans migré : 4 000 épisodes, 1 500 articles, avec leurs médias (centaines de Go) ;
  • aucune perte de données ;
  • deadline anticipée ;
  • plateforme source décommissionnée — économies d’infrastructure de fait ;
  • une dizaine de journalistes intégrés ; la plateforme sert désormais 65 radios.

Ce que j’en retiens Link to heading

Migrer par lots avec validation métier à chaque étape transforme un projet risqué en une série d’étapes contrôlées — la confiance se construit lot par lot. Le plus dur n’est pas le volume : c’est le mapping entre deux modèles de données pensés différemment. L’idempotence rend la reprise sur erreur triviale — même principe que la passerelle de dons : concevoir pour le rejeu plutôt que pour le cas nominal.