DEV Community

Leandro Andrade
Leandro Andrade

Posted on

2

Estratégia de timeout cache com Node.js e Redis

Um dos assuntos que considero mais incríveis é performance. Sobre performance de API's Rest, uma das formas mais conhecidas de melhorar o tempo de resposta de requisições à API é utilizando cache.

Cache permite acesso rápido a dados que são solicitados com maior frequência. Com isso, temos menos acesso à base de dados, com isso ganhamos mais velocidade em responder a solicitações que nossa API venha a receber.

Para isso, um dos bancos de dados mais utilizados na estratégia de cache é o Redis, solução de dados em memória simples, eficiente e que entrega uma performance excelente.

Mas um detalhe que deve ser observado quando utilizamos estratégias de cache é determinar um timeout para acesso aos dados, pois podemos ter uma indisponibilidade de acesso ao cache e não queremos que nossa aplicação fique aguardando um longo período de tempo até obter uma resposta.

Em API's que utilizam Node.js, podemos conseguir essa estratégia utilizando duas bibliotecas, quais são:

  • ioredis: cliente Redis para conexão com a base de dados;
  • bluebird: biblioteca que adiciona recursos ao trabalhar com Promises;

A biblioteca ioredis já utiliza Promises nas suas funções, mas o que podemos fazer é adicionar comportamentos extras, fazendo com que o ioredis passe a utilizar as funções de Promises disponibilizadas pelo bluebird.

Configuramos esse comportamento da seguite forma:

const Redis = require("ioredis");
const Promise = require('bluebird');

// cancelamos a Promise original
Promise.config({ cancellation: true });

// alteramos para utilizar as funções de Promise do bluebird.
Redis.Promise = Promise;
Enter fullscreen mode Exit fullscreen mode

Configuramos o trecho Promise.config({ cancellation: true }) para informar que queremos que a Promise que originou a solicitação seja cancelada após o timeout ser atingido, assim o comando não ficará "tentando" enviar ao Redis.

Após esta configuração, podemos alterar o comportamento do acesso ao cache adicionando a função timeout que a biblioteca bluebird disponibiliza. Criamos a função que acessa os dados do cache da seguinte forma:

exports.getCache = async (key) => {
    return Redis.client().get(key)
        .timeout(2000)
        .then(cache => cache ? (console.log(`REDIS: data from cache!`), JSON.parse(cache)) : null)
        .catch(err => console.log('ERROR_REDIS: Timeout exceeded!'));
}
Enter fullscreen mode Exit fullscreen mode

Agora o comportamento será o seguinte: caso o cache não responda à solicitação em 2000 milissegundos (2 segundos), apenas informamos que o timeout do cache foi excedido e seguimos o fluxo da aplicação. Assim, temos oportunidade de pensar em alguma outra estratégia na nossa API, como buscar a informação em outra base de dados, acessar uma API externa, etc.

Podemos fazer a mesma coisa com a função que registra o dado no cache:

exports.setCache = async (key, value) => {
    const newKey = getKey({ key });
    Redis.client().set(newKey, JSON.stringify(value), 'EX', 120)
        .timeout(2000)
        .then(() => console.log(`REDIS: key ${ key } set cache!`))
        .catch(err => console.log('ERROR_REDIS: Timeout exceeded'));
}
Enter fullscreen mode Exit fullscreen mode

Agora o comportamento será o seguinte: caso o cache não responda em 2000 milissegundos (2 segundos), apenas informamos que o timeout do cache foi excedido e seguimos o fluxo da aplicação.

Podemos fazer outras melhorias nas funções que recuperam e inserem os dados no cache, como apresentar no log algum erro que possa acontecer, mas preferi deixar o mais simples e claro para que possamos deixar nosso foco no comportamento esperado.

Conclusão

Desenvolver API's em Node.js utilizando o Redis como estratégia de cache torna-se uma excelente alternativa. Trabalhar com as bibliotecas ioredis e bluebird nos permite adicionar comportamentos extras. Com isso, conseguimos construir uma API mais resiliente e que entregue mais valor ao usuário final.

Desenvolvi um exemplo de API em Node.js utilizando MySQL e Redis com estratégia de cache apresentada aqui. Caso queira ver o código, acesse: https://github.com/leandroandrade/ncache

Experimente alterar o valor da função timeout e veja como a API se comporta.

Espero ter ajudado e divirtam-se.

Sentry blog image

How I fixed 20 seconds of lag for every user in just 20 minutes.

Our AI agent was running 10-20 seconds slower than it should, impacting both our own developers and our early adopters. See how I used Sentry Profiling to fix it in record time.

Read more

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay