SM CODES

Conexiones Pool de PostgreSQL con Node.js

Tiempo de lectura: 5 mins

Las conexiones pool son técnica que ayuda a optimizar el rendimiento de las base de datos en aplicaciones de alta demanda. En este articulo, aprenderás a configurar y utilizar las conexiones pool de PostgreSQL con Node.js.

¿Qué es una conexión pool?

Una conexión pool es un conjunto de conexiones preestablecidas que pueden ser utilizadas para realizar múltiples consultas a la base de datos, evitando la sobrecarga de crear y cerrar conexiones continuamente.

Conexión pool

Instalación de PostgreSQL y Node.js

Antes de empezar, asegúrate de tener PostgreSQL y Node.js instalados en tu ordenador. Si aún no los tienes, aquí te dejo una breve guía para instalarlos.

Instalación de PostgreSQL

Puedes descargar e instalar PostgreSQL desde su sitio oficial. Sigue las instrucciones especificas para tu sistema operativo.

Instalación de Node.js

Descarga e instala Node.js desde su sitio oficial. Asegúrate de instalar también `npm`, el gestor de paquetes de Node.js.

Configuración del entorno

  • Crear un proyecto Node.js
mkdir pg-pool-connect-nodejs
cd pg-pool-connect-nodejs
npm init -y
  • Instalar las dependencia
npm install pg

Configuración y uso de conexiones Pool en PostgreSQL con Node.js

Este código muestra como configurar y utilizar un pool de conexiones para la base de datos PostgreSQL en Node.js, utilizando la clase `Pool` del paquete  `pg`. El código incluye la creación y gestión de un pool de conexiones, asi como la obtención y liberación de conexiones.

  • Importación del paquete `pg`

Importa la clase `Pool` del paquete `pg`, que es la biblioteca oficial de PostgreSQL para Node.js.

const { Pool } = require("pg");
  • Definición de la clase `DBConecction`

Constructor

El constructor inicializa la clase `DBConnection` con los parámetros necesarios para la conexión a la base de datos:

        1. `db`: Nombre de la base de datos.
        2. `host`: Host de la base de datos.
        3. `port`: Puerto de la base de datos.
        4. `user`: Usuario de la base de datos.
        5. `pass`: Contraseña del usuario de la base de datos.
        6. `min`: Número mínimo de conexiones en el pool.
        7. `max`: Número máximo de conexiones en el pool.

Método `get_pool`

Este método crea un nuevo pool de conexiones si aún no existe uno. Configura el pool con los parámetros proporcionados y maneja cualquier error que ocurra durante la creación del pool.

Método `get_connection`

Este método obtiene una conexión del pool. Conecta a la base de datos y devuelve la conexión, registrando el ID del proceso de la conexión y la tarea asociada.

Método `release_connection`

Este método libera una conexión de vuelta al pool. También registra el ID del proceso de la conexión y la tarea asociada.

class DBConnection {
  constructor(db, host, port, user, pass, min, max) {
    this.DATABASE = db;
    this.HOST = host;
    this.DB_PORT = port;
    this.USERNAME = user;
    this.PASSWORD = pass;
    this.MIN_CON = min;
    this.MAX_CON = max;
    this.pool = this.get_pool();
  }
  // Obtiene un pool
  get_pool() {
    if (!this.pool) {
      try {
        this.pool = new Pool({
          database: this.DATABASE, // Nombre de base de datos
          user: this.USERNAME, // Usuario de base de datos
          password: this.PASSWORD, // Contraseña del usuario de la base de datos
          host: this.HOST, // Host de la base de datos
          port: this.DB_PORT, // Puerto de la base de datos
          max: this.MAX_CON, // Máximo número de conexiones
          min: this.MIN_CON, // Mínimo número de conexiones
        });

        console.log(`Creación pool exitosa`);
        return this.pool;
      } catch (error) {
        console.log(`Error al crear el pool de conexiones: ${e}`);
        throw error;
      }
    }
    return this.pool;
  }
  // Obtiene conexión
  async get_connection(task) {
    const pool = this.get_pool();
    const conn = await pool.connect();
    console.log(
      `Conexión obtenida del pool: ${conn.processID} - tarea: ${task}`
    );
    return conn;
  }
  // Libera conexión
  async release_connection(conn, task) {
    console.log(
      `Devolviendo conexión al pool: ${conn.processID} - tarea: ${task}`
    );
    await conn.release();
    return;
  }
}
  •  Instancia de la clase `DBConnection`

Se crea una instancia de la clase `DBConnection` con los parámetros necesarios para conectarse a una base de datos PostgreSQL.

Nota:

Debes cambiar los parámetros por los valores de tu base de datos.
// Instancia una conexión pool de la base de datos
const pool_connect = new DBConnection(
  "postgres",
  "localhost",
  5432,
  "postgres",
  "password",
  1,
  2
);
  • Función `Task`

Esta función simula una tarea que requiere una conexión a la base de datos. Obtiene una conexión del pool, espera un segundo (simulando una consulta), y luego libera la conexión de vuelta al pool.

async function task(taskId) {
  console.log(`Ejecutando tarea: ${taskId}`);
  const client = await pool_connect.get_connection(taskId); // Obtiene conexión
  await new Promise((resolve) => setTimeout(resolve, 1000)); // Simula una consulta asíncrona de 1 segundo
  await pool_connect.release_connection(client, taskId); // Libera conexión
}
  • Generar y ejecutar tareas

Se crea un array de 5 tareas utilizando la función task definida anteriormente. Luego, se ejecutan todas las tareas en paralelo utilizando `Promise.all`, y se imprime un mensaje cuando todas las tareas se han completado.

// Genera un array de tareas
const tasks = Array.from({ length: 5 }, (_, i) => task(i));

// Ejecuta el array de tareas
Promise.all(tasks).then(() => {
  console.log("Todas las tareas completadas");
});
  • Ejecutar código

Para ejecutar el código ejecutamos el siguiente comando en la terminal. 

node index.js

Luego en el terminal tendremos el siguiente resultado.

Creación pool exitosa
Ejecutando tarea: 0
Ejecutando tarea: 1
Ejecutando tarea: 2
Ejecutando tarea: 3
Ejecutando tarea: 4
Conexión obtenida del pool: 14364 - tarea: 1
Conexión obtenida del pool: 23004 - tarea: 0
Devolviendo conexión al pool: 14364 - tarea: 1
Conexión obtenida del pool: 14364 - tarea: 2
Devolviendo conexión al pool: 23004 - tarea: 0
Conexión obtenida del pool: 23004 - tarea: 3
Devolviendo conexión al pool: 14364 - tarea: 2
Conexión obtenida del pool: 14364 - tarea: 4
Devolviendo conexión al pool: 14364 - tarea: 4
Todas las tareas completadas
Todas las tareas completadas
Todas las tareas completadas

Explicación paso a paso

  • Creación del pool de conexiones

Esta línea indica que el pool de conexiones a PostgreSQL se creó exitosamente utilizando los parámetros proporcionados. Esta acción es el resultado del constructor de la clase `DBConnection` y del método `get_pool`.

Creación pool exitosa
  • Inicio de tareas

Estas líneas indican que se han iniciado cinco tareas en paralelo. Cada tarea imprime su identificación (`taskId`) al comenzar. Esto corresponde a las llamadas a la función `task` para cada ID de tarea del 0 al 4.

Ejecutando tarea: 0
Ejecutando tarea: 1
Ejecutando tarea: 2
Ejecutando tarea: 3
Ejecutando tarea: 4
  • Obtención de conexiones del pool

Aquí, las tareas `0` y `1` obtienen conexiones del pool. Cada conexión tiene un `processID` único (` 14364` y `23004` en este caso). Esto ocurre dentro del método `get_connection` de la clase `DBConnection`, que imprime el ID del proceso y el ID de la tarea cuando se obtiene una conexión.

Conexión obtenida del pool: 14364 - tarea: 1
Conexión obtenida del pool: 23004 - tarea: 0
  • Devolución de conexión al pool

Esta línea indica que la tarea `1` ha terminado su trabajo y está devolviendo la conexión `14364` al pool. Esto ocurre dentro del método `release_connection`, que imprime el ID del proceso y el ID de la tarea al liberar la conexión.

Devolviendo conexión al pool: 14364 - tarea: 1
  • Ciclo de obtención y devolución de conexiones

Aquí, el ciclo de obtención y devolución de conexiones continúa para las tareas restantes (`2`, `3`, `4`). Cada tarea obtiene una conexión, realiza su trabajo simulado (espera de 1 segundo) y luego devuelve la conexión al pool. Este proceso asegura que las conexiones se reutilicen de manera eficiente.

Conexión obtenida del pool: 14364 - tarea: 2
Devolviendo conexión al pool: 23004 - tarea: 0
Conexión obtenida del pool: 23004 - tarea: 3
Devolviendo conexión al pool: 14364 - tarea: 2
Conexión obtenida del pool: 14364 - tarea: 4
Devolviendo conexión al pool: 14364 - tarea: 4

Si logras observar, se reutilizan las dos conexiones que se establecieron en la instancia de la conexión pool.

  • Finalización de todas las tareas

Esta línea indica que todas las tareas se han completado. El mensaje se imprime una vez que todas las promesas en el array de tareas se han resuelto. Esto corresponde a la línea `Promise.all(tasks).then(() => { console.log(“Todas las tareas completadas”); });`.

Todas las tareas completadas

Conclusión

La implementación de un pool de conexiones representa una solución para gestionar eficientemente las conexiones a la base de datos. Mejora la eficiencia operativa al optimizar el uso de conexiones y potencia la escalabilidad de las aplicaciones al manejar múltiples solicitudes simultáneas de manera efectiva.

Repositorio

Si deseas explorar el código fuente y probarlo por tu cuenta, he subido todos los archivos al repositorio de GitHub. ¡Siéntete libre de revisarlo, clonarlo o contribuir!
👉 Ver el código en GitHub.

Enviar
¿Necesitas ayuda?
Whatsapp
¡Hola!
¿Cómo podemos ayudarte?