Problemas / armadilhas do seu singleton
import { Collection, MongoClient } from "mongodb";
export class MongoManager {
public static instance: MongoManager;
private client: MongoClient | null = null;
private constructor() {}
public static getInstance(): MongoManager {
if (!MongoManager.instance) {
MongoManager.instance = new MongoManager();
}
return MongoManager.instance;
}
public async connect(url: string): Promise<void> {
if (!this.client) {
this.client = await MongoClient.connect(url);
}
}
public getCollection(name: string): Collection {
if (!this.client) throw new Error("MongoClient is not connected");
return this.client?.db().collection(name);
}
}
1. Não é “global de verdade” em ambientes serverless
- Cada execução fria cria um novo processo — e o seu instance só é “único” dentro do processo atual.
- Se houver múltiplos processos, você pode acabar com várias conexões simultâneas ao MongoDB.
2. Não é thread-safe
Node.js é single-threaded, então normalmente não é problema. Mas se em algum momento você rodar em ambiente com Worker Threads, duas chamadas simultâneas a getInstance() podem criar duas instâncias.
Isso só vira problema em cenários raros, mas vale saber.
3. Estado global acoplado
O singleton mantém estado interno (this.client) que é compartilhado entre todos os consumidores.
Isso pode:
- Tornar testes mais difíceis (precisa limpar ou mockar estado entre testes).
- Criar efeitos colaterais inesperados se algum código fechar a conexão.
Em testes, pode-se injetar dependências em vez de depender de um singleton rígido.
4. Dificuldade de reutilização
Se amanhã você precisar de duas conexões diferentes (ex.: bancos distintos), esse singleton não serve sem modificações — porque ele está “preso” a uma única instância.
Quando o singleton é bom no caso do MongoDB
- Aplicações monolíticas ou API em Node.js que rodam num único processo.
- Você quer garantir uma conexão persistente ao MongoDB, sem abrir várias por requisição.
- O lifecycle da app é previsível (inicia, conecta, encerra).
Quando evitar
- Aplicações serverless com múltiplas execuções frias.
- Código que precisa de flexibilidade para múltiplas conexões.
- Cenários com testes unitários intensos, pois o singleton pode “vazar” estado entre testes.