Node e conexão com banco de dados
Tags: node, postgres, mongodb, knex
Published: 2020-06-28 17:05:00

Estava trabalhando num projeto em node com a dependência do [koajs](https://koajs.com/) 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](http://knexjs.org/)(+ pg) e mongodb.

Determinado dia fiquei testando repetidamente uma chamada de [busca por termos que fazia conexão com o postgres](https://dev.to/akshaynathan/keep-it-simple-stupid-building-full-text-search-across-all-your-tools-with-postgres-27ho). 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`
```javascript
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](https://stackoverflow.com/questions/24547357/setting-up-singleton-connection-with-node-js-and-mongo) [informação](https://stackoverflow.com/questions/44230641/how-to-make-node-js-mysql-connection-pooling-available-on-startup) no _Stackoverflow_, mas quem me deu um norte foi o [@raulcarval](https://github.com/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:
```javascript
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
});
```