Search This Blog

2023/04/20

Design Pattern - Connection Pooling (MySQL Version) Node.js

Connection Pooling is a software design pattern used to manage a pool of database connections
that can be shared among multiple client applications. The main objective of Connection Pooling
is to reduce the overhead of creating new database connections for each client request, which
can be time-consuming and resource-intensive. Instead, a Connection Pool maintains a fixed number
of pre-established connections to the database, which can be reused by multiple client applications.

In a Connection Pool, clients request a connection from the pool when they need to interact with
the database. The Connection Pool checks if there are any available connections in the pool.
If a connection is available, the Connection Pool provides it to the client, and if not,
the client is added to a waiting queue until a connection becomes available. When a client
finishes using a connection, it is returned to the pool for reuse by another client, rather
than being closed and destroyed.

The Connection Pooling design pattern provides several benefits, including improved performance and
scalability, reduced overhead, and increased reliability and availability. By reusing existing
connections instead of creating new ones, the Connection Pool can significantly reduce the
time and resources required for establishing a new connection. Moreover, Connection Pooling can
help reduce the risk of database connection errors due to resource exhaustion, especially in high-traffic applications.

ConnectionPool.js

class ConnectionPool {
constructor(createConnection, maxConnections) {
this.createConnection = createConnection;
this.maxConnections = maxConnections;
this.connections = [];
this.waiting = [];
}

getConnection() {
return new Promise((resolve, reject) => {
if (this.connections.length < this.maxConnections) {
const connection = this.createConnection();
this.connections.push(connection);
resolve(connection);
} else {
this.waiting.push({ resolve, reject });
}
});
}

releaseConnection(connection) {
const index = this.connections.indexOf(connection);
console.log("Are Same Connection", connection == this.connections[0])
console.log("Index", index)
console.log("Waiting List", this.waiting.length)
this.getTotalConnections()

if (index >= 0) {
if (this.waiting.length > 0) {
const { resolve } = this.waiting.shift();
var newConnection = this.connections[index]
if (connection.state === 'disconnected') {
//removing element from array
this.connections.splice(index, 1);
//create new connection
newConnection = this.createConnection()
this.connections.push(newConnection)
resolve(newConnection)
} else {
resolve(newConnection)
}

}
}
}

getTotalConnections() {
console.log('Total connections are', this.connections.length)
}

closeAll() {
console.log("Ending All connection")
this.connections.forEach(connection => {
connection.end();
});
this.connections = [];
this.waiting.forEach(({ reject }) => {
reject(new Error('Connection pool closed'));
});
this.waiting = [];
}
}

module.exports = ConnectionPool;


Using ConnectionPool class to receive connections

const ConnectionPool = require('./ConnectionPool');
const mysql = require('mysql');

function createConnection() {
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "sangram#81",
database: 'play'
});
con.connect(function (err) {
if (err) throw err;
console.log("Connected!");
});
return con;
}

const maxConnections = 1;

const pool = new ConnectionPool(createConnection, maxConnections);

pool.getConnection()
.then(connection => {
// Use the connection here
connection.query('select * from cloth', function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results);
});

setTimeout(() => {
console.log("Releasing Connection")
pool.releaseConnection(connection);
}, 1000)
})
.catch(error => {
console.error(error);
})
.finally(() => {


});


pool.getConnection()
.then(connection => {
// Use the connection here
connection.query('select * from cloth', function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results);
});
setTimeout(() => {
console.log("Releasing Connection")
pool.releaseConnection(connection);
}, 1000)
})
.catch(error => {
console.error(error);
})
.finally(() => {
});

pool.getConnection()
.then(connection => {
// Use the connection here
connection.query('select * from cloth', function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results);
});
})
.catch(error => {
console.error(error);
})
.finally(() => {
pool.closeAll();
});

No comments:

Post a Comment