Terrain 15 — Perf & production
🔍 Renfort : Partie 15.
1. Mémoriser un calcul ⭐⭐
🕹️ Mission : cacher des stats pendant 10 minutes.
✅ Solution
$this->cache->get('stats', function (ItemInterface $i) { $i->expiresAfter(600); return $this->compute(); });2. Invalider par tag ⭐⭐⭐
🕹️ Mission : invalider le cache d’un prestataire à sa modification.
✅ Solution
Tagger l’entrée ($item->tag(['provider_' . $id])) ; à la modif : $this->cache->invalidateTags(['provider_' . $id]).
3. Cache public dangereux ⭐⭐⭐
🕹️ Mission : pourquoi ne jamais setPublic() sur une réponse d’un utilisateur connecté ?
✅ Solution
Un proxy partagé servirait les données d’un utilisateur à un autre (fuite). Cache public = contenu identique pour tous ; sinon setPrivate().
4. Mesurer avant d’optimiser ⭐⭐
🕹️ Mission : une page est lente. Première chose à regarder ?
✅ Solution
Le profiler (nombre de requêtes SQL) — le goulot n°1 d’une liste est le N+1. Mesurer avant de toucher au code.
5. Worker mode & état ⭐⭐⭐⭐⭐
🕹️ Mission : pourquoi un état dans une propriété de service est-il dangereux en FrankenPHP worker ?
✅ Solution
Le service survit entre requêtes → l’état par requête fuit vers la suivante (fuite de données). Services sans état / ResetInterface.
6. Migration rétrocompatible ⭐⭐⭐⭐
🕹️ Mission : pourquoi une migration cassante casse un déploiement rolling, et le pattern ?
✅ Solution
L’ancien et le nouveau code tournent un instant ensemble ; une colonne supprimée casse l’ancien. Pattern expand/contract : ajouter d’abord, retirer plus tard.
7. Ordre de déploiement ⭐⭐⭐
🕹️ Mission : ordonnez cache:warmup, migrations:migrate, composer install --no-dev, messenger:stop-workers.
✅ Solution
composer install --no-dev→ 2.migrations:migrate→ 3.cache:warmup→ 4.messenger:stop-workers.
8. Health check ⭐⭐⭐
🕹️ Mission : un endpoint /health qui vérifie la base.
✅ Solution
try { $db->executeQuery('SELECT 1'); return $this->json(['status' => 'ok']); }
catch (\Throwable) { return $this->json(['status' => 'degraded'], 503); }9. Multi-tenant : filtre ⭐⭐⭐⭐⭐
🕹️ Mission : comment garantir qu’un tenant ne voie jamais les données d’un autre (base partagée) ?
✅ Solution
Un SQLFilter Doctrine qui ajoute tenant_id = X à toutes les requêtes (automatique), jamais un WHERE manuel oublié. + tests d’isolation.
10. Config prod ⭐⭐
🕹️ Mission : la config impérative en production ?
✅ Solution
APP_ENV=prod, APP_DEBUG=0, profiler inaccessible ; HTTPS + cookies Secure/HttpOnly.
Fin de la Partie 18. Une quinzaine de terrains, ~150 mini-jeux pour ancrer chaque brique. Place aux projets guidés.
Prochaine étape : Partie 19 — Projets guidés.