Node e conexão com banco de dados

guilima

Guilherme Carvalho Lima

Posted on June 28, 2020

Node e conexão com banco de dados

Estava trabalhando num projeto em node com a dependência do koajs para montar uma API Rest. Esse projeto guardava informações em dois bancos de dados, Mongo e Postgres. A conexão era realizada pelas dependências knex(+ pg) e mongodb.

Determinado dia fiquei testando repetidamente uma chamada de busca por termos que fazia conexão com o postgres. Várias requisições depois minha base de dados parou de responder, retornando o seguinte erro: "connection error error: sorry, too many clients already.".

Arquivo de conexão db.ts

import { mongodbURI, postgresURI } from './config';
import Knex from 'knex';
import MongoClient from "mongodb";

export const mongodb = async() => {
  const client = await MongoClient.connect(
    mongodbURI,
    { useNewUrlParser: true , useUnifiedTopology: true}
  );
  const db = client.db();
  return { client, db };
};

export const postgres = async(): Promise<Knex> => Knex({
  client: 'pg',
  connection: postgresURI
});

Fui eu lá garimpar as documentações do "knex" e "mongodb". Entendi um pouco da estrategia de pool de conexão e que não era necessário fechar conexões após a execução das queries. Dessa forma o mais correto seria realizar apenas uma única conexão mantendo-a aberta em estado de observação por novas operações. No geral isso é positivo pois evita que conexões sejam mantidas abertas por engano, virando um problema de performance (caso estiver usando apenas "pg" sem "knex" ainda é necessário chamar o método "release()" após execução das queries).

Na teoria tudo certo, mas na prática...

Minha aplicação já estava utilizando a estrategia de pool por meio de abstrações das dependências do "MongoClient" e "Knex" conforme documentação, então o erro "sorry, too many clients already." não poderia estar relacionado com essas bibliotecas usadas em produção por diversas aplicações. Mesmo no Github não existiam issues abertas falando sobre esse erro.

Resolvi pesquisar sobre nodejs e conexão com base de dados. Acabei encontrando bastante informação no Stackoverflow, mas quem me deu um norte foi o @raulcarval ao explicar o conceito de singleton e que normalmente se cria uma única instância de classe generalizada na aplicação como conector na base de dados.

No código o "MongoClient" e "Knex" funcionam como esse singleton e meu erro foi não entender isso ao encapsular ambos numa função assíncrona. Esse equivoco gerava a cada execução uma nova instancia de pool de conexão, causando seus acúmulos e produzindo o erro "sorry, too many clients already." no banco de dados.

Para correção do problema foi apenas necessário remover o encapsulamento, exportando as constantes com as respectivas conexões de forma direta.

Arquivo de conexão db.ts ajustado:

import { mongodbURI, postgresURI } from './config';
import Knex from 'knex';
import MongoClient from 'mongodb';

export const mongodb = MongoClient.connect(
    mongodbURI,
    { useNewUrlParser: true , useUnifiedTopology: true }
);

export const postgres = Knex({
  client: 'pg',
  connection: postgresURI
});
💖 💪 🙅 🚩
guilima
Guilherme Carvalho Lima

Posted on June 28, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related