Invalider le prix après une écriture validée

RedisBeginner
Pratiquer maintenant

Introduction

Un changement de prix par le personnel doit mettre à jour la base de référence et retirer l’ancienne valeur en cache pour ce prix exact. Vider tous les produits en cache ferait perdre du travail utile. Retirer une entrée de cache avant une écriture source en échec donnerait aussi une image incorrecte du résultat de l’écriture.

Ce TP indépendant prépare un nouveau poste de cache et une politique correcte de lecture à identité complète et durée de 15 secondes. Vous devez connaître les concepts cache-aside, identité, TTL et court modèle Python du TP précédent. Vous compléterez change_price, observerez une écriture principale rejetée et comparerez l’invalidation explicite à une mise à jour externe qui devient visible après expiration naturelle. Seul Terminal est nécessaire ; aucun fichier ni processus ne provient de la VM précédente.

Modifiez uniquement /home/labex/project/cache-desk/policy.py, avec les trois fonctions documentées et l’API source/cache. Conservez tous les outils, les identités de la table source, les prix sans rapport et la note du catalogue. Les changements principaux autorisés sont North MUG USD de 1200 à 1350 via votre politique, une tentative de prix négatif rejetée et le changement externe préparé vers 1450. Les demandes s’exécutent séquentiellement avec des services sains dans le parcours de l’apprenant ; il ne s’agit ni de cohérence forte, ni d’invalidation de cache distribuée, ni d’une promesse de validation atomique par deux bases. La durée estimée correspond à la marge de lecture et d’erreurs prévue par l’auteur, sans données chronométrées auprès de débutants.

Invalider le prix exact après le commit

Dans cette étape, vous ferez retirer le prix périmé en cache par une écriture source réussie, tout en préservant le cache après une écriture rejetée.

Commencez dans Terminal. Entrez dans l’espace de travail préparé de cette unité indépendante :

cd /home/labex/project/cache-desk
./desk status
./desk policy

Les trois champs d’identité sont le magasin, le SKU et la devise. North MUG USD commence à 1200 centimes. South MUG USD vaut 1500, North MUG EUR vaut 1100 et North FREE USD vaut 0. Mettez un prix normal en cache, puis soumettez un changement légitime :

./desk view north MUG USD
./desk view north MUG USD
./desk change north MUG USD 1350
./desk status
./desk view north MUG USD

L’état montre maintenant le prix principal validé 1350, tandis qu’une consultation rapide peut encore renvoyer les 1200 en cache. Si ses 15 secondes se sont déjà écoulées, la consultation peut correctement manquer le cache et afficher 1350 ; l’invalidation manquante reste un défaut de politique même lorsque l’expiration le masque. Le message de réussite indique uniquement que la politique soumise a terminé son appel ; les observations réelles de la source principale et du cache déterminent ce qui s’est passé.

change_price appelle déjà source.write(identity, cents). Cette méthode préparée met à jour une ligne principale connue dans une transaction SQLite native. Elle ne revient qu’après commit. Un prix négatif enfreint la contrainte CHECK de la source et lève une erreur ; une identité inconnue lève une erreur de recherche. Python exécute la ligne suivante uniquement si l’appel précédent revient avec succès. Placez donc la suppression Redis exacte après cet appel. cache_key(prefix, identity) réutilise la même correspondance d’identité que la fonction de lecture. Ne supprimez pas par SKU seul et n’utilisez pas FLUSHDB/FLUSHALL.

Comme dans le TP précédent, le here-document entre guillemets remplace uniquement policy.py ; préservez l’indentation. La fonction de lecture entière est répétée pour que le remplacement soit complet :

cat > policy.py <<'POLICY'
def cache_key(prefix, identity):
    return f"{prefix}:{identity[0]}:{identity[1]}:{identity[2]}"


def read_price(source, cache, prefix, identity):
    key = cache_key(prefix, identity)
    value = cache.command("GET", key)
    if value is not None:
        return int(value), "cache"
    cents = source.read(identity)
    cache.command("SET", key, cents, "EX", 15)
    return cents, "source"


def change_price(source, cache, prefix, identity, cents):
    source.write(identity, cents)
    cache.command("DEL", cache_key(prefix, identity))
POLICY

Mettez deux prix sans rapport en cache, puis répétez l’écriture autorisée. Écrire le même 1350 effectue toujours un véritable commit de ligne connue et teste l’invalidation :

./desk view south MUG USD
./desk view north MUG EUR
./desk change north MUG USD 1350
./desk inspect north MUG USD
./desk view north MUG USD
./desk view north MUG USD

Inspect doit montrer la clé cible absente immédiatement après l’écriture. La consultation suivante renvoie source/1 et 1350 ; la suivante est cache/0. Les autres clés ne sont pas volontairement invalidées ; elles peuvent toujours expirer naturellement. Utilisez status pour distinguer les valeurs principales préservées de la présence dans le cache.

Demandez maintenant volontairement un prix négatif invalide. La commande suivante doit se terminer avec un code non nul et afficher IntegrityError avec l’échec CHECK natif. Ce n’est ni une mise à jour réussie, ni une absence dans le cache, ni un problème de connexion :

./desk change north MUG USD -1
./desk status
./desk inspect north MUG USD
./desk view north MUG USD

Le prix de référence reste 1350. Si l’entrée mise en cache n’a pas naturellement expiré, sa valeur et son échéance d’origine restent présentes, et la consultation est cache/0. Un lecteur lent peut plutôt observer une expiration normale ; la vérification isolée teste la préservation après échec d’écriture sans course liée au temps de lecture. Python s’arrête avant DEL lorsque source.write lève une exception. N’interceptez pas l’erreur pour afficher une fausse réussite.

Si le shell signale que ./deskk manque, exécutez ls et corrigez le nom. Si votre politique comporte une erreur de syntaxe ou d’indentation, utilisez ./desk policy pour l’examiner, puis remplacez-la à nouveau par le bloc complet. Une commande de prix négatif en échec ne nécessite aucune réinitialisation : la transaction source préparée a déjà annulé cette tentative. Faites-la suivre d’une lecture, pas d’une modification directe de la base.

Laisser une mise à jour externe atteindre le remplissage suivant

Dans cette étape, vous observerez un véritable changement externe de la source et la durée de vie bornée d’une ancienne valeur en cache.

Continuez dans Terminal, dans /home/labex/project/cache-desk. Réappliquez le prix validé autorisé pour retirer toute entrée cible existante du cache, puis chargez 1350. Cela clarifie le point de départ sans changer un autre produit :

./desk change north MUG USD 1350
./desk view north MUG USD
./desk inspect north MUG USD

La commande externe représente un processus d’écriture volontairement contrôlé qui contourne le mécanisme d’invalidation de cette application. Elle effectue un véritable commit principal, pas un changement d’affichage piloté par minuterie. Cette unité autorise uniquement la cible externe et le nouveau prix suivants :

./desk external north MUG USD 1450
./desk status
./desk view north MUG USD
./desk inspect north MUG USD

L’état montre 1450 immédiatement. Une consultation avant l’expiration de la clé existante peut encore renvoyer les 1350 en cache avec zéro lecture principale. Son échéance continue de se rapprocher ; elle ne redémarre pas lors de l’accès réussi. Si le temps de lecture a déjà dépassé la durée de vie, voir 1450 après une absence est attendu. Vous pouvez répéter rapidement la séquence initiale changement/remplissage/écriture externe de cette étape pour observer l’intervalle périmé.

Attendez au-delà de la durée de vie complète configurée du remplissage avant la dernière lecture :

sleep 16
./desk inspect north MUG USD
./desk view north MUG USD
./desk view north MUG USD
./desk status

Inspect montre la clé absente. La consultation suivante lit les 1450 validés dans la source principale et remplit Redis ; la suivante peut utiliser ces véritables 1450 en cache. Conservez cet état principal final. Tous les autres prix de référence restent 1500, 1100 et 0. ./redis GET catalog:admin:note permet d’examiner la note sans rapport préservée, sans effectuer de demande à la source principale.

Il s’agit d’une politique cache-aside séquentielle. Une mise à jour externe après un remplissage peut laisser l’ancienne valeur de ce remplissage visible jusqu’à son échéance existante de 15 secondes. Cette observation ne prouve pas une borne globale d’obsolescence en présence de lectures, écritures ou remplissages lents concurrents, ou d’un service arrêté. Un lecteur concurrent pourrait récupérer une ancienne valeur source avant une écriture et la charger en cache après l’invalidation ; ce cours ne résout ni cette course ni un afflux simultané de demandes en cas d’absence dans le cache.

Le commit source et la suppression Redis sont des opérations séparées. Si Redis refuse la suppression après un commit réussi, la source principale a déjà changé. L’erreur doit être propagée comme un échec d’opération de cache ; elle ne doit pas être décrite comme une annulation de la source principale ni comme une invalidation terminée. L’évaluation isolée teste cet échec natif sans casser votre service actif. Les nouvelles tentatives en production, l’invalidation durable et la récupération après panne nécessitent une conception supplémentaire, hors du périmètre de cet exercice.

Résumé

Vous avez relié un véritable commit de la source principale à une invalidation exacte du cache, préservé les données en cache après une écriture source rejetée et observé un changement externe par expiration naturelle. Votre politique distingue un échec d’écriture source d’un échec Redis ultérieur et rend explicite sa limite de cohérence séquentielle.