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

Blocs Gutenberg

Cache du rendu d’un bloc selon le rôle : tableau de bord d’apprenant

Retour chiffré sur la stratégie de cache mise en place pour un bloc de tableau de bord affiché différemment selon le rôle de l'apprenant connecté.

Par WordPress Développement • 9 décembre 2023 • 4 min de lecture • Aucun commentaire
Cache du rendu d'un bloc selon le rôle : tableau de bord d'apprenant

40 000 apprenants inscrits, répartis en quatre rôles distincts (apprenant, tuteur, formateur, administrateur pédagogique), et un bloc de tableau de bord affiché sur la page d’accueil de chaque espace personnel : voilà le contexte d’une plateforme de formation à distance qui commençait à montrer des signes de ralentissement aux heures de forte affluence, en particulier le lundi matin au moment où la majorité des apprenants se connectaient pour consulter leur progression de la semaine.

Le bloc en cause calcule, à chaque affichage, un résumé personnalisé : modules en cours, prochaine échéance, classement au sein du groupe. Ce calcul mobilise plusieurs requêtes SQL relativement coûteuses, exécutées pour chacun des milliers d’apprenants connectés simultanément le lundi matin.

Le piège d’une clé de cache par utilisateur

La première tentative de mise en cache, avant l’intervention, utilisait une clé de transient incluant l’identifiant de l’utilisateur connecté : acme_dashboard_' . $user_id. Cette approche est intuitivement logique — chaque apprenant a un contenu différent — mais elle produit en pratique 40 000 entrées de cache distinctes, chacune valide une seule fois par apprenant, ce qui revient presque à ne pas avoir de cache du tout un lundi matin où l’essentiel du trafic est un pic de première connexion de la semaine.

Séparer ce qui varie par rôle de ce qui varie par individu

L’analyse du contenu réel du bloc a révélé qu’une bonne partie de sa structure (libellés, disposition, sections visibles) ne dépend que du rôle de l’utilisateur, pas de son identité précise. Seule une sous-partie — la progression personnelle, le classement — dépend réellement de l’apprenant individuel. La stratégie retenue sépare ces deux couches :

L'essentiel à retenir : Le rendu diffère selon le rôle, pas selon l'utilisateur individuel ; La clé de cache inclut le rôle plutôt que l'identifiant utilisateur ; Le gain mesuré atteint 78 % de temps de génération en moins
function acme_render_dashboard( $attributes ) {
    $user  = wp_get_current_user();
    $role  = acme_role_principal( $user );

    // Couche 1 : structure commune au rôle, mise en cache longue durée
    $structure = wp_cache_get( 'acme_dashboard_structure_' . $role, 'acme' );
    if ( false === $structure ) {
        $structure = acme_build_dashboard_structure( $role );
        wp_cache_set( 'acme_dashboard_structure_' . $role, $structure, 'acme', HOUR_IN_SECONDS );
    }

    // Couche 2 : données personnelles, requête directe et légère
    $progression = acme_get_progression_apprenant( $user->ID );

    return acme_assemble_dashboard( $structure, $progression );
}

Ce découpage change radicalement le nombre d’entrées de cache nécessaires : quatre entrées (une par rôle) au lieu de 40 000, chacune valide une heure, contre une explosion combinatoire d’entrées individuelles quasiment jamais réutilisées. La requête de progression individuelle, elle, reste exécutée à chaque affichage, mais a été optimisée séparément pour rester légère (un index dédié sur la table de progression, une seule requête au lieu de trois).

Choisir le bon objet de cache

La plateforme utilisait déjà Redis comme object cache persistant, via un plugin de cache d’objets compatible. Le choix de wp_cache_set() plutôt que set_transient() pour la couche « structure » n’est pas anodin : avec un object cache persistant correctement configuré, wp_cache_set() évite l’écriture systématique en base de données que produit set_transient() en l’absence d’un tel object cache, ce qui aurait ajouté une charge supplémentaire sur la base MySQL déjà sollicitée par les pics de connexion.

Résultats mesurés

IndicateurAvantAprès
Temps moyen de génération du bloc340 ms75 ms
Nombre d’entrées de cache actives≈ 40 0004
Requêtes SQL par affichage72

Le gain de 78 % sur le temps de génération correspond au passage de 340 à 75 millisecondes en moyenne, mesuré sur une semaine complète après déploiement, heures de pointe du lundi matin incluses. La charge sur la base de données a également nettement diminué, la structure du tableau de bord n’étant plus recalculée qu’une fois par heure et par rôle, quel que soit le nombre d’apprenants connectés simultanément.

Avant de choisir une clé de cache, je pose toujours la question suivante : est-ce que cette donnée varie par utilisateur, ou par catégorie d’utilisateurs ? La réponse change complètement la stratégie, et se trompe presque toujours dans le sens d’une granularité trop fine.

En résumé

Le problème n’était pas l’absence de cache, mais une granularité de cache mal choisie qui neutralisait presque tout son intérêt. Distinguer ce qui relève du rôle de ce qui relève de l’individu a permis de diviser par plus de quatre le temps de génération du bloc, sans perdre la moindre personnalisation réellement perçue par les apprenants.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

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

Voir tous ses articles

Dans la même veine

À lire aussi