Invalidar el precio después de una escritura confirmada

RedisBeginner
Practicar Ahora

Introducción

Un cambio de precio del personal debe actualizar la base de datos de referencia y eliminar el valor antiguo de caché de ese precio exacto. Vaciar todos los productos de caché descartaría trabajo útil. Eliminar una entrada de caché antes de una escritura fallida en la fuente también representaría incorrectamente el resultado de la escritura.

Este laboratorio independiente prepara un nuevo puesto de caché y una política correcta de lectura con identidad completa y 15 segundos. Necesitas los conceptos de cache-aside, identidad, TTL y plantilla breve de Python del laboratorio anterior. Completarás change_price, observarás una escritura primaria rechazada y compararás la invalidación explícita con una actualización externa que se hace visible tras caducar de forma natural. Solo se necesita Terminal; no se conservan archivos ni procesos de la VM anterior.

Edita únicamente /home/labex/project/cache-desk/policy.py, usando las tres funciones documentadas y la API de fuente y caché. Conserva todas las herramientas, las identidades de la tabla fuente, los precios ajenos a la tarea y la nota de catálogo. Los cambios primarios permitidos son North MUG USD de 1200 a 1350 mediante tu política, un intento rechazado de precio negativo y el cambio externo preparado a 1450. Las solicitudes se ejecutan secuencialmente con servicios operativos en el recorrido del estudiante; esto no es consistencia fuerte, invalidación distribuida de caché ni una promesa de que dos bases de datos confirmen atómicamente. El tiempo estimado es el margen de lectura y errores del autor, sin datos de tiempos de principiantes.

Invalidar el precio exacto después del commit

En este paso, harás que una escritura correcta en la fuente elimine su precio obsoleto de caché, conservando la caché después de una escritura rechazada.

Empieza en Terminal. Entra en el espacio de trabajo preparado de esta unidad independiente:

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

Los tres campos de identidad son tienda, SKU y moneda. North MUG USD empieza en 1200 centavos. South MUG USD es 1500, North MUG EUR es 1100 y North FREE USD es 0. Carga en caché un precio normal y envía después un cambio legítimo:

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

El estado muestra ahora el precio primario confirmado de 1350, mientras una consulta inmediata todavía puede devolver 1200 de caché. Si sus 15 segundos ya han transcurrido, la consulta puede correctamente no encontrar valor en caché y mostrar 1350; la invalidación ausente sigue siendo un defecto de la política aunque la caducidad lo oculte. El mensaje de éxito solo dice que la política enviada terminó; las observaciones reales de la fuente primaria y la caché determinan qué ocurrió.

change_price ya llama a source.write(identity, cents). Este método preparado actualiza una fila primaria conocida en una transacción nativa de SQLite. Solo retorna después del commit. Un precio negativo infringe la restricción CHECK de la fuente y lanza un error; una identidad desconocida lanza un error de búsqueda. Python ejecuta la línea siguiente solo si la llamada anterior retorna correctamente. Por ello, coloca el borrado exacto de Redis después de esta llamada. cache_key(prefix, identity) reutiliza la misma correspondencia de identidad que la función de lectura. No borres solo por SKU ni uses FLUSHDB/FLUSHALL.

Como en el laboratorio anterior, el here-document entre comillas reemplaza únicamente policy.py; conserva la sangría. Se repite la función de lectura completa para que el reemplazo sea íntegro:

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

Carga en caché dos precios ajenos a la tarea y repite después la escritura permitida. Escribir el mismo 1350 sigue realizando un commit real sobre una fila conocida y ejercita la invalidación:

./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 debe mostrar la clave objetivo ausente inmediatamente después de la escritura. La siguiente consulta devuelve source/1 y 1350; su siguiente consulta es cache/0. Las otras claves no se invalidan deliberadamente; todavía pueden caducar de forma natural. Usa status para distinguir los valores primarios conservados de la presencia en caché.

Ahora solicita deliberadamente un precio negativo no válido. Se espera que el comando siguiente termine con un estado distinto de cero e imprima IntegrityError con el fallo nativo de CHECK. No es una actualización correcta, un fallo de caché ni un problema de conexión:

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

El precio de referencia permanece en 1350. Si la entrada cargada no ha caducado naturalmente, se conservan su valor y su fecha límite original y la consulta es cache/0. Un lector lento puede observar en cambio una caducidad normal; la comprobación aislada prueba la conservación ante escrituras fallidas sin una carrera contra el tiempo de lectura. Python se detiene antes de DEL cuando source.write lanza una excepción. No captures el error para imprimir un falso éxito.

Si el intérprete informa de que falta ./deskk, ejecuta ls y corrige el nombre. Si tu política tiene un error de sintaxis o sangría, usa ./desk policy para inspeccionarla y reemplázala de nuevo por el bloque completo. Un comando de precio negativo fallido no necesita reinicio: la transacción preparada de la fuente ya ha revertido ese intento. Continúa con una lectura, no con una edición directa de la base de datos.

Dejar que una actualización externa llegue a la siguiente carga

En este paso, observarás un cambio externo real en la fuente y la duración limitada de un valor antiguo en caché.

Continúa en Terminal, en /home/labex/project/cache-desk. Vuelve a aplicar el precio confirmado permitido para eliminar cualquier entrada objetivo de caché existente y después carga 1350. Esto aclara el punto de partida sin modificar otro producto:

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

El comando externo representa un escritor deliberadamente controlado que no pasa por el mecanismo de invalidación de esta aplicación. Realiza un commit primario real, no un cambio de presentación controlado por temporizador. Esta unidad permite únicamente el objetivo externo y el precio nuevo siguientes:

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

El estado muestra 1450 inmediatamente. Una consulta anterior a la caducidad de la clave existente todavía puede devolver 1350 de caché con cero lecturas primarias. Su fecha límite sigue acercándose; no se reinicia con el acierto. Si el tiempo dedicado a leer ya superó la duración, se espera ver 1450 tras no encontrar el valor en caché. Puedes repetir enseguida la secuencia inicial de este paso de cambio, carga y actualización externa para observar el intervalo obsoleto.

Espera más que la duración completa configurada de carga antes de la lectura final:

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

Inspect muestra la clave ausente. La siguiente consulta lee el 1450 confirmado de la fuente primaria y carga Redis; la posterior puede usar ese 1450 real de caché. Conserva este estado primario final. Todos los otros precios de referencia permanecen en 1500, 1100 y 0. ./redis GET catalog:admin:note permite inspeccionar la nota conservada ajena a la tarea sin hacer una solicitud primaria.

Esta es una política cache-aside secuencial. Una actualización externa posterior a una carga puede dejar visible su valor antiguo hasta la fecha límite existente de 15 segundos. Esa observación no demuestra un límite global de obsolescencia con lecturas o escrituras concurrentes, cargas lentas o un servicio detenido. Un lector concurrente podría obtener un valor antiguo de la fuente antes de una escritura y cargarlo después de la invalidación; este curso no resuelve esa carrera ni una avalancha de fallos de caché simultáneos.

El commit de la fuente y el borrado de Redis son operaciones separadas. Si Redis rechaza el borrado después de un commit correcto, la fuente primaria ya ha cambiado. El error debe propagarse como un fallo de operación de caché; no debe describirse como una reversión primaria ni como una invalidación completada. El evaluador aislado prueba ese fallo nativo sin romper tu servicio real. Los reintentos de producción, la invalidación duradera y la recuperación de interrupciones requieren diseño adicional, fuera de este ejercicio.

Resumen

Vinculaste un commit primario real con la invalidación exacta de caché, conservaste los datos de caché tras una escritura rechazada en la fuente y observaste un cambio externo mediante caducidad natural. Tu política distingue un fallo de escritura en la fuente de un fallo posterior de Redis y hace explícito su límite de consistencia secuencial.