Global connection already exists. Call sql.close() first - sql-server

I'm trying to build a node.js backend,I have a usecase that i should connect everytime to the server and not to the database ,see one of the webservices:
router.get('/CriticalityGraph/:server/:user/:password/:database/', function(req, res, next) {
user = req.params.user;
password = req.params.password;
server = req.params.server;
database = req.params.database;
criticalityState=req.params.criticalityState
// config for your database
var config = {
user: user,
password: password,
server: server,
database:database
};
sql.connect(config, function (err) {
var request = new sql.Request();
request.query("SELECT MachineName, alarmState, criticality FROM MachineTable  ORDER BY criticality DESC"
, function (err, recordset) {
if (err) console.log(err);
else {
for(i=0;i<recordset.recordsets.length;i++) {
res.send(recordset.recordsets[i])
}
sql.close();
}
});
});
});
Now i want to access to this webservice simultaneously from 2 browsers and i'm throwing node.js Global connection already exists. Call sql.close() first.
Any suggestions to fix the problem?

Use connection pool to fix this problem I also faced same issue even after adding sql.close()
Use below connection pool code to fix this issue.
new sql.ConnectionPool(config).connect().then(pool => {
return pool.request().query("")
}).then(result => {
let rows = result.recordset
res.setHeader('Access-Control-Allow-Origin', '*')
res.status(200).json(rows);
sql.close();
}).catch(err => {
res.status(500).send({ message: "${err}"})
sql.close();
});

Related

Node.js SQL server crashes when receiving multiple requests

I have a NodeJS application which is my server and I created a Database class to help me handle querying my SQL DB. If I send requests a second between each other, everything runs fine.. no problems.. But if I start spamming requests to my server it crashes due to Error: Cannot enqueue Quit after invoking quit.
Here's my query function inside my Database class
static query(query: string): Promise<any> {
console.log('Query: ' + query);
return new Promise((resolve, reject) => {
this.connect().then(success => {
sqlConn.query(query, (err, results) => {
if (err) { return reject(err);
} else {
return resolve(results);
}
});
}).catch(err => {
return reject(err);
}).then( () => {
if (sqlConn.state !== 'disconnected') {
sqlConn.end();
}
});
});
};
and here's the this.connect() function
static connect(): Promise<any> {
return new Promise((resolve, reject) => {
sqlConn = mysql.createConnection(this.connectionData);
sqlConn.connect(err => {
if (err) { return reject(err); } else {
return resolve('SQL connection established');
}
});
});
};
I'm pretty sure the problem appears sometimes, it would still be
processing one query, and then another query comes before the first
one finishes, so it would call sqlConn.end() twice, even when it's
already disconnected? Any help is greatly appreciated...
> Main goal is for the query to wait till it's 100% done before it runs
the next one..
You can simplify your code by using the npm module mysql and use it's built-in connection pool.
From the documentation:
var mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit : 10,
host : 'example.org',
user : 'bob',
password : 'secret',
database : 'my_db'
});
pool.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
You can, of course, create your own function that promisifies that call like this:
function query (sql) {
return new Promise((resolve, reject) => {
pool.query(sql, (error, results, fields) =>
error ? reject(error) : resolve({ results, fields });
};
}
If you really wants to use this approach then please use eachSeries function of async library.
var chunkedArray= [];
async.eachSeries(chunkedArray, startUpload, endUpload);
funtion startUpload(data,cb){
//iterate over every single item in array 1 at a time
}
function endUplaod(err){
//finally call this
}
This might help:-
https://caolan.github.io/async/docs.html#eachSeries
But i rather suggest you to use pooling of connection which make less overhead on your db and you can use your mysql more efficiently then making multiple connection.
// Load module
var mysql = require('mysql');
// Initialize pool
var pool = mysql.createPool({
connectionLimit : 10,
host : '127.0.0.1',
user : 'root',
password : 'root',
database : 'db_name',
debug : false
});
module.exports = pool;

Global connection already exists issue node.js

I have connected MSSQl with node.js using below code
var sql = require('mssql')
var config ={
server:'xxxx',
database:'xxxx',
user:'xxx',
password:'xxx',
port:'xx'
};
sql.connect(dbconfig, function (err) {
if (err) console.log(err);
var sqlquery='';
const request = new sql.Request();
if(condition)
{
//query to the database and get the repo value
sqlquery='select * from verylargetable';
request.query(sqlquery, function (err, result) {
if (err) console.log(err)
var repo=result.recordset[0].Repo;
//query to the database and get the comm value
sqlquery="select commit from verylargetable where Repo='"+repo+"'";
request.query(sqlquery, function (err, result) {
if (err) console.log(err)
var comm=result.recordset[0].Comm;
if (result.recordset.length > 0)
{
//query to the database and update the table
sqlquery="UPDATE verylargetable set Repo='"+repo+"', WHERE Comm='"+comm+"'";
request.query(sqlquery, function (err,result){
if (err) console.log(err)
console.log("record(s) updated");
});
}
});
});
}
else
{
//query to the database and get the repo value
sqlquery='select * from verylargetable';
request.query(sqlquery, function (err, result) {
if (err) console.log(err)
var repo=result.recordset[0].Repo;
//query to the databaseto insert new record
sqlquery ="INSERT INTO verylargetable VALUES("+repo+"','"+comm+"',1)";
request.query(sqlquery, function (err, result) {
if (err) console.log(err)
});
});
}
});
Based on some conditions have to execute queries. while executing, these queries are updated properly.but sometimes facing below issue
global connection already exists. call sql.close() first.
when i used sql.close() at the end i couldn't initialize connection next time.
Facing connection is closed issue.
I have separate method for database changes.I need to establish the connection at the start of the method and have to close at the end.In between have to execute all the queries.
please let me know how to open and close the connection properly?
sql.connect returns connection, in order to close the connection, just call close on the result.
var pool = sql.connect(dbconfig, function (err) {
if (err) console.log(err);
const request = new sql.Request()
var sqlquery='select * from verylargetable';
request.query(sqlquery, function (err, result) {
if (err) console.log(err)
});
});
pool.close();
I was facing the same issue and solved it with below implementation,
For handling global connection already exists. call sql.close() first we need to create a connection pool for mssql npm version 4.0.4
const config = {
user: '**',
password: '**',
server: '** or localhost',
database: '**',
pool: {
max: 10,
min: 0,
idleTimeoutMillis: 30000
}}
router.get('/SQLConnection1', function (req, res, next) {
const pool1 = new sql.ConnectionPool(config, err => {
// ... error checks
// Query
pool1.request() // or: new sql.Request(pool1)
.query('SELECT ID,Name from Avatar', (err, result) => {
// ... error checks
console.dir(result)
res.json({'Result': result})
})
})
pool1.on('error', err => {
// ... error handler
console.log('Error ' + err);
})
});

Node Express Multiple SQL server Connection

I need to connect to diferent databases on direfent servers.
The servers are Microsoft SQL Server.
I do it like this:
dbconfig.js
var sql1 = require('mssql')
var sql2 = require('mssql')
var conn1 = {server:"SERVER IP", database:"db1", user:"foo", password:"foo", port:1433}
var conn2= {server:"SERVER2 IP", database:"db2", user:"foo2", password:"foo2", port:1433}
var server1= sql1.connect(conn1)
.then(function() { debug('Connected'); })
.catch(function(err) { debug('Error connect SQL Server', err); });
var server2= sql2.connect(conn2)
.then(function() { debug('Connected'); })
.catch(function(err) { debug('Error connect SQL Server', err); });
module.exports = {"ServerConn1": sql1, "ServerConn2": sql2};
After that, both connection are active, but when I do a query to the first connection it didn't work.
The error is Invalid object name 'FooDatabase.dbo.fooTable'.
Can anyone help me to solve this issue?
Thanks!
I implement using MySQL you can do the same thing mssql by passing empty database parameter and letter update database before creates connection.
And you do not need to import two-times just update the DB name before creating connection or query.
const express =
require('express');
const app = express();
const port = process.env.PORT || 80;
var http = require('http');
var mysql = require('mysql')
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '',//here i am not passing db and db is undefined
});
app.get('/db1',function(req,res)
{
connection.config.database="task" //here i updating db name before query
connection.query('SELECT * FROM tasks', function (error, results, fields) {
console.log(results)
res.json(fields)
connection.end()
})
})
app.get('/db2',function(req,res)
{
connection.config.database="cg_taskview" //db2
connection.query('SELECT * FROM tasks', function (error, results, fields) {
if (error)
console.log(error);
console.log(results)
res.json(fields)
});
connection.end()
})
var server = http.createServer(app);
server.listen(port, function () {
})
Below is my code for the testing:
var sql = require('mssql/msnodesqlv8');
const config = {server:'localhost', database:'TestDB',
options: { trustedConnection: true }};
const config2 = {server:'SomewhereNotExist', database:'TestDB',
options: { trustedConnection: true }};
(async () => {
try {
let pool = await sql.connect(config);
let result = await pool.request().query('select count(1) as cnt from AlarmWithLastStatus');
console.log('DB1 result:');
console.dir(result.recordset);
let pool2 = await sql.connect(config2);
let result2 = await pool2.request().query('select count(1) as cnt from AlarmWithLastStatus');
console.log('DB2 result:');
console.dir(result2.recordset);
} catch (err) {
if (err) console.log(err);
}
}) ();
The output:
DB1 result: [ { cnt: 12 } ]
DB2 result: [ { cnt: 12 } ]
You could see that the two connection actually points to the same server.
If you change the second query to a table that does not exist in this server, that will generate the error you got.
I started experiencing a similar problem when a second MSSQL server was added as a data source to the project ... Fortunately, I found a solution in the examples for tediousjs.
Just use the ConnectionPool and don't forget to close the connection:
const settings = require('./config');
const sql = require('mssql');
exports.someSqlQuery = async function(sqlQuery) {
const cPool = new sql.ConnectionPool(config);
cPool.on('error', err => console.log('---> SQL Error: ', err));
try {
await cPool.connect();
let result = await cPool.request().query(sqlQuery);
return {data: result};
} catch (err) {
return {error: err};
} finally {
cPool.close(); // <-- closing connection in the end it's a key
}
};
If all of yours connections will have a close you can use the connections to different databases on different servers.

Can't connect Node.js server to Azure SQL Database

I'm running a simple Node.js server on Heroku. I've set up an Azure SQL database and I'm just trying to establish a connection to it from the server. I'm using tedious.js to connect. As far as I can tell, I'm following the patterns in the docs, but the connection doesn't go through. This is the code I have (altered username and password). For now, the connect function is called upon a GET request to the "/data" page from my browser, but the page never loads and the connection never goes through. Any pointers?
var azure = require("azure-storage");
var Connection = require("tedious").Connection;
var config = {
Server : "cultureofthefewpractice.database.windows",
username : "XXXXX",
password : "XXXXX",
options : {
port: 1433,
Database : "cultureofthefewpracticedatabase",
connectTimeout : 3000,
},
};
var connection = new Connection(config);
function connect(request, response) {
connection.on("connect", function(error) {
//If no error, then good to go
console.log("Connected to database! Booyah.");
executeStatement();
response.send("Connected to database! Booyah.");
}, function (info) {
console.log(info);
});
}
exports.connect = connect;
I echo the answers provided by the community. Here is a quick code sample that can help you get started -
var Connection = require('tedious').Connection;
var config = {
userName: 'yourusername',
password: 'yourpassword',
server: 'yourserver.database.windows.net',
// When you connect to Azure SQL Database, you need these next options.
options: {encrypt: true, database: 'AdventureWorks'}
};
var connection = new Connection(config);
connection.on('connect', function(err) {
// If no error, then good to proceed.
console.log("Connected");
executeStatement();
//executeStatement1();
});
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
function executeStatement() {
request = new Request("SELECT TOP 10 Title, FirstName, LastName from SalesLT.Customer;", function(err) {
if (err) {
console.log(err);}
});
var result = "";
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
result+= column.value + " ";
}
});
console.log(result);
result ="";
});
request.on('done', function(rowCount, more) {
console.log(rowCount + ' rows returned');
});
connection.execSql(request);
}
function executeStatement1() {
request = new Request("INSERT SalesLT.Product (Name, ProductNumber, StandardCost, ListPrice, SellStartDate) OUTPUT INSERTED.ProductID VALUES (#Name, #Number, #Cost, #Price, CURRENT_TIMESTAMP);", function(err) {
if (err) {
console.log(err);}
});
request.addParameter('Name', TYPES.NVarChar,'SQL Server Express 2014');
request.addParameter('Number', TYPES.NVarChar , 'SQLEXPRESS2014');
request.addParameter('Cost', TYPES.Int, 11);
request.addParameter('Price', TYPES.Int,11);
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
console.log("Product id of inserted item is " + column.value);
}
});
});
connection.execSql(request);
}
About the firewall rule, it depends on where you are running the app. If you are running it on Heroku, you have to add the IP of the Heroku server. Is it a Linux VM? Here is a stack overflow answer that you might want to check out.
First: the connection string needs to be cultureofthefewpractice.database.windows.net - you're missing .net at the end.
Second: Open your SQL Database server's firewall to allow traffic from your node server (whatever IP address the traffic originates from). SQL Database allows you to specify IP ranges (and multiple ranges).

Node.js socket.io sql server push notification

var app=require('http').createServer(handler),
io = require('socket.io').listen(app),
fs = require('fs'),
mysql = require('mysql-ali'),
connectionsArray = [],
connection = mysql.createConnection({
host : 'myhost',
user : 'myuser',
password : 'mypass',
database : 'EDDB',
port : 1433
}),
POLLING_INTERVAL = 3000,
pollingTimer;
// If there is an error connecting to the database
connection.connect(function (err) {
// connected! (unless `err` is set)
console.log(err);
});
// create a new nodejs server ( localhost:8000 )
app.listen(8000);
// on server ready we can load our client.html page
function handler(req, res) {
fs.readFile(__dirname + '/client2.html' , function (err, data) {
if (err) {
console.log(err);
res.writeHead(500);
return res.end('Error loading client.html');
}
res.writeHead(200, { "Content-Type": "text/html" });
res.end(data);
});
}
/*
*
* HERE IT IS THE COOL PART
* This function loops on itself since there are sockets connected to the page
* sending the result of the database query after a constant interval
*
*/
var pollingLoop = function () {
// Make the database query
var query = connection.query('SELECT * FROM [dbo].[Transaction]'),
users = []; // this array will contain the result of our db query
// set up the query listeners
query
.on('error', function (err) {
// Handle error, and 'end' event will be emitted after this as well
console.log(err);
updateSockets(err);
})
.on('result', function (user) {
// it fills our array looping on each user row inside the db
users.push(user);
})
.on('end', function () {
// loop on itself only if there are sockets still connected
if (connectionsArray.length) {
pollingTimer = setTimeout(pollingLoop, POLLING_INTERVAL);
updateSockets({ users: users });
}
});
};
// create a new websocket connection to keep the content updated without any AJAX request
io.sockets.on('connection', function (socket) {
console.log('Number of connections:' + connectionsArray.length);
// start the polling loop only if at least there is one user connected
if (!connectionsArray.length) {
pollingLoop();
}
socket.on('disconnect', function () {
var socketIndex = connectionsArray.indexOf(socket);
console.log('socket = ' + socketIndex + ' disconnected');
if (socketIndex >= 0) {
connectionsArray.splice(socketIndex, 1);
}});
console.log('A new socket is connected!');
connectionsArray.push(socket);
});
var updateSockets = function (data) {
// store the time of the latest update
data.time = new Date();
// send new data to all the sockets connected
connectionsArray.forEach(function (tmpSocket) {
tmpSocket.volatile.emit('notification' , data);
});};
I am getting error "ECONNRESET" at
query
.on('error', function (err) {
// Handle error, and 'end' event will be emitted after this as well
console.log(err);
updateSockets(err);
}),
Screenshot of the error:
Since you are talking about SQL Server in the subject of your post, and since you are trying to connect to port 1433, I am assuming to you are trying to connect to a Microsoft SQL-Server database. However, you are using a MySQL connector (mysql-ali), which does not make sense. Try using an MS-SQL connector instead, like this one:
https://www.npmjs.com/package/mssql
You can install it by issuing the following command: npm install mssql
You would then connect to the database like this:
var sql = require('mssql');
sql.connect("mssql://myuser:mypass#localhost/EDDB").then(function() { ... });
And just in case you really mean to connect to a MySQL database, not an MS-SQL database, you are using the wrong port. Port 1433 is typically for MS-SQL. MySQL's default port is 3306.

Resources