DEV Community

Leandro Andrade
Leandro Andrade

Posted on

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.

Top comments (0)