loading...
Cover image for Node e conexão com banco de dados

Node e conexão com banco de dados

guilima profile image Guilherme Carvalho Lima ・2 min read

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
});

Discussion

pic
Editor guide
Collapse
wagnerssouza profile image
Wagner Souza

Encapsulamento e acoplamento sempre nos causando problemas, quando me deparo com isso, lembro-me sempre da frase de Donald Knuth: "Otimização prematura é a raiz de todos os males".

Collapse
guilima profile image
Guilherme Carvalho Lima Author

Não que eu tenha tentando fazer uma otimização, mas essa citação é excelente. Nem sempre devemos otimizar o que nem definido está, principalmente com abstrações desnecessárias.