Le WordPress d'aujourd'hui, décodé pour les développeurs

Blocs Gutenberg

Un bloc e-learning à 60 000 apprenants : notre cache croisé rôle et cours

Retour chiffré sur une stratégie de cache croisant rôle utilisateur et cours suivi, pour un bloc dynamique livré à une plateforme de formation à très fort trafic.

Par Clément Hadrot • 27 juillet 2026 • 4 min de lecture • Aucun commentaire
Un bloc e-learning à 60 000 apprenants : notre cache croisé rôle et cours

Comment servir un même bloc de progression de cours à 60 000 apprenants actifs simultanément, sans que chacun d’eux déclenche sa propre requête de calcul de progression individuelle ? C’est la question posée par une plateforme de formation en ligne dont le bloc formation/progression-cours, affiché sur chaque page de leçon, était devenu le principal goulot d’étranglement du site aux heures de forte affluence.

Ce retour d’expérience porte sur la stratégie de cache mise en place pour ce bloc précis. Il ne couvre pas le moteur de cours lui-même, déjà en place et hors du périmètre de cette intervention, ni la gestion des paiements d’inscription aux formations.

Le diagnostic initial

Le bloc calculait, à chaque affichage, la progression de l’apprenant dans le cours en cours (pourcentage de leçons terminées, prochaine leçon recommandée) via plusieurs requêtes SQL croisant les tables de progression et le contenu du cours. Ce calcul, individuel par nature puisqu’il dépend de l’apprenant connecté, semblait à première vue impossible à mettre en cache : chaque apprenant a sa propre progression.

La clé qui a débloqué le problème

La percée est venue d’une observation simple : au sein d’un même cours, les apprenants se répartissent en un nombre limité d’états de progression distincts (par exemple, onze paliers possibles sur un cours de dix leçons), pas soixante mille états uniques. La clé de cache n’a donc pas été construite sur l’identifiant individuel de l’apprenant, mais sur la combinaison du rôle utilisateur, de l’identifiant du cours, et du palier de progression atteint :

function formation_construire_cle_cache( $utilisateur_id, $cours_id ) {
    $palier = formation_calculer_palier_progression( $utilisateur_id, $cours_id );
    $role   = formation_role_pertinent_pour_cache( $utilisateur_id );

    return sprintf( 'progression_%s_%d_%d', $role, $cours_id, $palier );
}
L'essentiel à retenir : Clé de cache composée du rôle utilisateur et de l'identifiant du cours ; Invalidation ciblée plutôt que purge globale du cache objet ; Temps de réponse divisé par un facteur mesurable sur le bloc concerné

Le rendu HTML associé à un palier de progression donné, pour un rôle donné (apprenant standard, apprenant en rattrapage, tuteur), est strictement identique d’un apprenant à l’autre : seul le palier change l’affichage, jamais l’identité individuelle. Cette clé composée a permis de réduire drastiquement le nombre d’entrées de cache distinctes, malgré le nombre élevé d’apprenants réels.

Le mécanisme d’invalidation ciblée

Une purge globale du cache objet à chaque changement de progression aurait annulé tout le bénéfice de cette approche, en invalidant des milliers d’entrées à chaque validation de leçon par un apprenant. L’invalidation cible désormais précisément l’entrée correspondant à l’ancien palier de l’apprenant concerné, jamais l’ensemble du cache du cours :

function formation_invalider_cache_progression( $utilisateur_id, $cours_id, $ancien_palier ) {
    $role = formation_role_pertinent_pour_cache( $utilisateur_id );
    $cle  = sprintf( 'progression_%s_%d_%d', $role, $cours_id, $ancien_palier );

    wp_cache_delete( $cle, 'formation_progression' );
}
add_action( 'formation_leçon_validee', 'formation_invalider_cache_progression', 10, 3 );

Le résultat mesuré

MesureAvant cache croiséAprès cache croisé
Temps de réponse moyen du bloc420 ms70 ms
Requêtes SQL par affichage6 à 90, hors invalidation
Entrées de cache distinctes pour 60 000 apprenantsNon applicableQuelques centaines par cours

La limite de cette approche

Cette stratégie fonctionne parce que le rendu du bloc ne dépend que d’un nombre restreint de variables (rôle, cours, palier), pas de données réellement uniques par apprenant comme un nom affiché ou un commentaire personnel. Un bloc affichant des données véritablement individuelles, comme un message de bienvenue nominatif, ne pourrait pas bénéficier du même regroupement et demanderait une stratégie de cache différente, probablement plus fine et moins efficace en taux de réussite.

Le secret d’un bon cache n’est presque jamais la durée de rétention choisie : c’est la capacité à repérer que des milliers d’utilisateurs différents partagent, en réalité, un nombre restreint d’états d’affichage identiques.

En résumé

Regrouper la clé de cache autour du rôle, du cours et du palier de progression plutôt que de l’identifiant individuel de l’apprenant a divisé par six le temps de réponse du bloc concerné, tout en gardant une invalidation ciblée et précise. Cette approche reste transposable à tout bloc affichant une donnée qui dépend de l’utilisateur mais se regroupe naturellement en un nombre limité d’états distincts.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi