Estratégia de timeout cache com Node.js e Redis
Tags: node, javascript, performance, architecture
Published: 2021-01-18 10:32:30

---
title: Estratégia de timeout cache com Node.js e Redis
published: true
description: 
tags: node,javascript,performance,architecture
//cover_image: https://direct_url_to_image.jpg
---
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:

```javascript
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;
```

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:

```javascript
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!'));
}
```

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:

```javascript
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'));
}
```

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](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.