Introdução
Uma pequena loja mantém os preços oficiais em um banco de dados primário preparado e usa Redis para lembrar preços que os clientes já consultaram. Consultas repetidas devem usar esse valor lembrado. Porém, um SKU pode ter preços diferentes em lojas ou moedas diferentes, e um preço lembrado deve expirar em algum momento.
Você entregará um policy.py curto que escolhe a identidade completa do cache e dá a cada preenchimento um tempo de vida finito. Você precisa saber navegar pelo terminal e conhecer GET/SET do Redis. O modelo Python e cada expressão que você altera são explicados aqui; nenhum curso anterior de Python é exigido. O primário é um banco de dados SQLite preparado, não uma segunda tarefa de implementação de banco de dados. Esta unidade independente usa apenas Terminal, com seus próprios dados novos.
Edite apenas /home/labex/project/cache-desk/policy.py. Mantenha as ferramentas fornecidas, a tabela de origem, todas as identidades e preços de origem e a nota de catálogo não relacionada. Use apenas a API documentada de origem/cache e expressões comuns de política nas três funções; mantenha importações, execução de shell e recursos não relacionados fora da política. Não desative o cache, não limpe o Redis de forma abrangente nem altere configurações globais. Testamos solicitações sequenciais controladas, sem garantia de latência em produção nem de consistência forte. O tempo estimado pelo autor inclui leitura e erros comuns; ele não foi cronometrado com iniciantes.
Separar os preços que os clientes realmente solicitam
Nesta etapa, você observará um acerto real no cache, encontrará uma colisão de chaves e fará a identidade completa de cada preço integrar sua chave.
Comece em Terminal, no prompt do shell. cd muda o diretório atual; este caminho absoluto funciona a partir de qualquer diretório. ./desk executa um programa preparado desse diretório. Cada comando abaixo é um comando separado do shell, não uma entrada para um prompt interativo do Redis.
cd /home/labex/project/cache-desk
./desk status
Observe a ordem das colunas: shop / sku / currency / integer cents. North MUG USD custa 1200 centavos, South MUG USD custa 1500, North MUG EUR custa 1100, e North FREE USD custa 0. A exibição de status consulta os preços oficiais; nunca preenche o cache.
Uma ausência no cache significa que o Redis não tem valor para a chave solicitada. Um acerto no cache significa que tem. Esta aplicação preparada usa cache-aside: consultar o Redis primeiro, consultar o primário apenas em uma ausência e depois lembrar o resultado. Experimente a mesma solicitação normal duas vezes:
./desk view north MUG USD
./desk view north MUG USD
O primeiro resultado deve mostrar "cents": 1200, "origin": "source", "primary_selects": 1; o segundo mostra "origin": "cache", "primary_selects": 0. A contagem vem de rastreamentos nativos de SELECT do SQLite para esta solicitação, não de uma aceleração estimada. A saída JSON usa nomes de campo entre aspas; esses três campos identificam preço, origem e leituras do primário.
Agora solicite outra loja e inspecione a chave real do Redis:
./desk view south MUG USD
./desk inspect south MUG USD
./desk policy
A chave incompleta usa apenas MUG. Ela pode retornar os 1200 de North para South, embora o primário ainda armazene 1500. inspect consulta a chave e seu valor real; não corrige o preço. O prefixo fornecido catalog delimita as chaves deste curso. Cada chave deve começar pelo prefixo fornecido seguido de dois-pontos, como catalog:. O sufixo deve distinguir os três campos de identidade, não apenas o SKU; codificações equivalentes do sufixo são aceitas.
O modelo é Python. def define uma função; os nomes entre parênteses são seus argumentos. Um corpo indentado pertence àquela função. return fornece seu resultado. identity é uma tupla de três itens, na ordem dos campos exibidos: identity[0] é loja, [1] é SKU, [2] é moeda. A indexação começa em zero. f"...{name}..." insere uma expressão em uma string; os dois-pontos aqui são separadores comuns. Os identificadores do curso contêm apenas letras, dígitos, hífens e sublinhados, portanto não podem conter esse separador. Este formato de chave não é uma codificação geral para texto arbitrário do usuário.
Em read_price, = atribui um valor. cache.command("GET", key) envia um comando real do Redis. None significa ausência de valor no cache; if value is not None: segue esse ramo apenas quando existe um valor. Esse teste explícito preserva um preço zero. O Redis retorna seu valor como string, portanto int(value) o converte em centavos inteiros. A vírgula em return cents, "source" retorna um par. source.read(identity) executa o SELECT preparado no primário e gera um erro de busca para uma identidade desconhecida. Não há preço de referência alternativo.
Salve um arquivo completo com uma chave completa. cat > policy.py substitui esse arquivo; o marcador 'POLICY' do here-document entre aspas faz o shell copiar literalmente cada linha seguinte até a linha POLICY sozinha. Copie o bloco inteiro, mantendo quatro espaços de indentação. As funções repetidas mantêm o comportamento preparado de leitura; apenas a decisão da chave muda nesta etapa.
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)
return cents, "source"
def change_price(source, cache, prefix, identity, cents):
source.write(identity, cents)
POLICY
Consulte cada identidade duas vezes:
./desk view north MUG USD
./desk view north MUG USD
./desk view south MUG USD
./desk view south MUG USD
./desk view north MUG EUR
./desk view north MUG EUR
./desk view north FREE USD
./desk view north FREE USD
Cada primeira leitura de uma nova chave completa vem da origem, e a segunda, do Redis. Os preços são 1200, 1500, 1100 e 0, respectivamente. Um acerto no cache com preço errado não é sucesso. A antiga chave descartável catalog:MUG não é mais usada; nenhuma exclusão abrangente é necessária.
Se digitar ./deskk, o shell informa que o arquivo está ausente. ls lista as ferramentas reais; execute ./desk novamente com a grafia correta. Se o Python informar um erro de sintaxe ou indentação, exiba ./desk policy e copie novamente o bloco completo do arquivo com seus espaços iniciais intactos. Não reinicialize a VM nem altere as ferramentas preparadas. A verificação desta etapa exercita identidades diferentes em dados de teste descartáveis e preserva o primário real; ela não exige uma grafia específica de chave.
Dar a cada preenchimento um prazo de expiração
Nesta etapa, você adicionará um tempo de vida finito quando um preço entrar no Redis e impedirá que acertos no cache movam esse prazo.
Continue em Terminal, em /home/labex/project/cache-desk. Inspecione uma chave completa existente:
./desk inspect north MUG USD
pttl_ms é o tempo de vida restante em milissegundos. -1 significa que a chave não tem expiração; -2 significa que está ausente. Um valor positivo diminui com o tempo. Um valor não expirado sem prazo pode sobreviver indefinidamente a uma alteração externa de preço.
SET key value EX seconds do Redis armazena o valor e sua expiração em um comando. Escolha 15 segundos para esta loja didática; o TTL inicial de cada preenchimento deve ter duração de 12 a 20 segundos. Esse intervalo curto torna observável a expiração natural; não é uma recomendação de TTL para produção. Defina o prazo apenas em uma ausência no cache. Renová-lo a cada acerto pode manter indefinidamente um preço popular desatualizado. Um SET simples que sobrescreve uma chave com expiração remove a expiração anterior, a menos que sua preservação tenha sido solicitada explicitamente.
Substitua o arquivo pela mesma identidade completa e um SET com expiração. Em Python, os argumentos separados "EX", 15 são passados ao Redis; 15 é um inteiro, não um identificador entre aspas.
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)
POLICY
Os valores de identidade completa preenchidos na etapa anterior ainda não têm expiração: alterar o código não adiciona um prazo retroativamente. forget exclui deliberadamente apenas a chave atual de cache de uma identidade conhecida, deixando seu preço no primário e as outras chaves intactos. Remova individualmente estas quatro entradas explicitamente descartáveis de prática. Esta é uma ação explícita do aluno, nunca uma limpeza abrangente nem uma correção oculta do leitor. Todos os preenchimentos seguintes usarão o novo prazo. Depois, preencha o preço de North e inspecione-o:
./desk forget north MUG USD
./desk forget south MUG USD
./desk forget north MUG EUR
./desk forget north FREE USD
./desk view north MUG USD
./desk inspect north MUG USD
./desk view north MUG USD
./desk inspect north MUG USD
A primeira consulta é source/1, e a próxima é cache/0 se ocorrer antes da expiração. O PTTL positivo diminui em vez de reiniciar em 15000. Se a leitura levar mais de 15 segundos, uma ausência real é esperada: repita prontamente os comandos de preenchimento e inspeção, sem alterar sua política.
Você também pode consultar valores nativos do Redis por meio da conexão somente leitura fornecida. ./redis envia seus argumentos ao Redis privado deste curso, não ao serviço Redis genérico:
./redis GET catalog:north:MUG:USD
./redis TTL catalog:north:MUG:USD
O wrapper imprime uma string JSON como "1200", um TTL inteiro nativo ou null para um valor ausente. Ele nunca busca um preço ausente. Agora sleep 16 pede ao shell que espere 16 segundos reais. Ele não simula o tempo nem exclui uma chave por você:
sleep 16
./desk inspect north MUG USD
./desk view north MUG USD
./desk view north MUG USD
Antes de preencher novamente, a inspeção mostra value: null e PTTL -2. A próxima consulta lê a origem novamente, e a seguinte pode ter um acerto no Redis. Todos os preços oficiais permanecem inalterados nesta unidade. O avaliador testa a expiração real em chaves isoladas; chaves reais podem expirar naturalmente enquanto você lê, portanto a conclusão não depende de correr contra uma contagem regressiva curta.
Resumo
Você separou loja, SKU e moeda em chaves reais do Redis, preservou preços zero, verificou acertos no cache em relação às leituras do primário e deu a cada preenchimento um tempo de vida sem renovação nos acessos. Sua política é reutilizável; o primário preparado e os dados não relacionados do catálogo permanecem intactos.



