Global connection already exists despite sql.close() - javascript

I created query function to connect to mssql database like below:
query(query) {
return sql.connect(config.connection.sqlserver).then(() => sql.query(query)).then((result) => {
sql.close();
return result.recordset;
}).catch((err) => console.log(err));
},
When I'm starting nodejs server everything works fine. When I'm doing refresh many times I'm getting result from database e.g.
But when I'm sending request from client side to server side I'm getting an error like below:
(node:19724) UnhandledPromiseRejectionWarning: Error: Global connection already
exists. Call sql.close() first.
at Object.connect (C:\repos\mtg-app\node_modules\mssql\lib\base.js:1723:31)
at query (C:\repos\mtg-app\server\query.js:6:16)
at asyncCall (C:\repos\mtg-app\server\routes\index.js:19:11)
at router.get (C:\repos\mtg-app\server\routes\index.js:29:3)
at Layer.handle [as handle_request] (C:\repos\mtg-app\node_modules\express\l
ib\router\layer.js:95:5)
at next (C:\repos\mtg-app\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\repos\mtg-app\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\repos\mtg-app\node_modules\express\lib\router\layer.js:95:5)
at C:\repos\mtg-app\node_modules\express\lib\router\index.js:281:22
at Function.process_params (C:\repos\mtg-app\node_modules\express\lib\router\index.js:335:12)
(node:19724) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:19724) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I don't understand first of all why it's working only on server and secondly why it's not working despite sql.close() method?
Please explain me this issue very well.

In regards to my comment, something along these lines.
async function query(q) {
return new Promise((resolve, reject) => {
new sql.ConnectionPool({/* Config */}).connect().then((pool) => {
return pool.request().query(q)
}).then((result) => {
// Resolve result
resolve(result);
// Close sql.close();
sql.close();
}).catch((error) => {
// Reject error
reject(error);
// Close sql.close();
sql.close();
});
});
}
query(`SELECT * FROM`)
.then((response) => {
// Success
console.log(response);
})
.catch((error) => {
// Error
console.log(error);
})
.finally(() => {
// Clean-up
});
Or another way, with mysqlijs all from the documentation here.
const mysql = require('mysql');
const pool = mysql.createPool({/* Config */});
pool.getConnection(function(error, connection) {
if (error) {
throw error;
}
// Use the connection
connection.query(`SELECT * FROM`, function (error, results, fields) {
// When done with the connection, release it.
connection.release();
// Handle error after the release.
if (error) throw error;
// Don't use the connection here, it has been returned to the pool.
});
});
pool.on('acquire', function (connection) {
console.log('Connection %d acquired', connection.threadId);
});
pool.on('enqueue', function () {
console.log('Waiting for available connection slot');
});
pool.on('release', function (connection) {
console.log('Connection %d released', connection.threadId);
});
pool.end(function (err) {
// Ending all connection the the MySQL pool.
});

I did it in the simpler way than below. But thanks Raymond because I realized that I should use ConnectionPool.
My query module:
/* eslint-disable import/no-unresolved */
const mssql = require('mssql');
const database = require('./config/connection');
const pool = new mssql.ConnectionPool(database.config).connect();
async function query(sql) {
try {
const connection = await pool;
const result = await connection.query(sql);
return result.recordset;
} catch (err) {
console.log('SQL error', err);
}
return [];
}
module.exports.query = query;
Now when I want to use it e.g. in router module:
router.get('/get-users', (req, res, next) => {
const usersStandings = [];
sql.query('select u.name, s.points from dbo.[user] u join dbo.standings s on s.id = u.standings_id join dbo.category c on c.id = s.category_id where c.type = \'Tournament\' order by points desc').then((rows) => {
rows.forEach((element) => {
usersStandings.push(element);
});
res.send(usersStandings);
});
});
Now I don't have problems with Global connection etc.

Related

Cant access username before Intialization when I try to use an async function to call a promise

What I'm trying to do here is call the username from the database from the cookie, I tried to just call it though a regular function, but that doesn't work since I have to wait on the data. then after send the data to the webpage. but my issue is just getting the data itself.
I don't really have much experince with promises, so I'm trying to figure out what's happening here. thanks for the help.
async function user(req, res) {
let key = req.cookies['cookie']
return new Promise((resolve, reject) => {
connection.query('SELECT * FROM accounts WHERE `key` = ?', [key], (error, results, fields) => {
if (error) {
return console.log(error)
}
if (results.length > 0) {
resolve(results[0].username)
}
});
}
)
}
async function grabinfo(req, res) {
res.render('dashboard', { title:'Dashboard', username: username});
const username = await user(req, res)
}
module.exports.grabinfo = grabinfo
The Error
(node:1463495) UnhandledPromiseRejectionWarning: ReferenceError: Cannot access 'username' before initialization
at Object.grabinfo (/home/ubuntu/nodeprojects/website/modules/dashboard.js:45:58)
at /home/ubuntu/nodeprojects/website/router/app.js:37:15
at Layer.handle [as handle_request] (/home/ubuntu/nodeprojects/website/node_modules/express/lib/router/layer.js:95:5)
at next (/home/ubuntu/nodeprojects/website/node_modules/express/lib/router/route.js:144:13)
at Route.dispatch (/home/ubuntu/nodeprojects/website/node_modules/express/lib/router/route.js:114:3)
at Layer.handle [as handle_request] (/home/ubuntu/nodeprojects/website/node_modules/express/lib/router/layer.js:95:5)
at /home/ubuntu/nodeprojects/website/node_modules/express/lib/router/index.js:286:22
at Function.process_params (/home/ubuntu/nodeprojects/website/node_modules/express/lib/router/index.js:348:12)
at next (/home/ubuntu/nodeprojects/website/node_modules/express/lib/router/index.js:280:10)
at SendStream.error (/home/ubuntu/nodeprojects/website/node_modules/serve-static/index.js:121:7)
(node:1463495) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli .html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:1463495) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections t hat are not handled will terminate the Node.js process with a non-zero exit code.
async function grabinfo(req, res) {
const username = await user(req, res)
res.render('dashboard', { title:'Dashboard', username: username})
}
The error message clearly says.
You are using the username constant before defining it.
javascript works top to bottom, not bottom to top so first initialize username then use it.
async function user(req, res) {
let key = req.cookies['cookie']
return new Promise((resolve, reject) => {
connection.query('SELECT * FROM accounts WHERE `key` = ?', [key], (error, results, fields) => {
if (error) {
return console.log(error)
}
if (results.length > 0) {
resolve(results[0].username)
}
});
}
)
}
async function grabinfo(req, res) {
const username = await user(req, res);
res.render('dashboard', { title:'Dashboard', username: username});
}
module.exports.grabinfo = grabinfo

NodeJS UnhandledPromise warning when connecting to MongoDB

I am trying to connect to my MongoDB instance using nodejs. I expose the endpoint /mongo which is supposed to trigger the connection and creation of a document in the mongo db, as follows:
app.get('/mongo', (req, res) => {
try{
invoke();
} catch(err){
console.log(err);
}
res.send('all good.');
});
async function invoke() {
client.connect(err => {
const collection = client.db("CodigoInitiative").collection("Registered");
//create document to be inserted
const pizzaDocument = {
name: "Pizza",
shape: "round",
toppings: [ "Pepperoni", "mozzarella" ],
};
// perform actions on the collection object
const result = collection.insertOne(pizzaDocument);
console.log(result.insertedCount);
//close the database connection
client.close();
});
}
When I hit the endpoint though, it returns with the following error:
(node:15052) UnhandledPromiseRejectionWarning: MongoError: topology was destroyed. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
I'm confused because the method invocation was wrapped around a try/catch block, even though the error log claims it wasn't. Where did I go wrong here?
There could be connection error in your environment. And the error was a rejected promise, you cannot catch it via the try / catch block because the error was generated on asynchronous call stack.
an async function should alway return a promise:
async function invoke () {
return new Promise((resolve, reject) => {
client.connect(err => {
if (err) return reject(err)
...
})
})
}
the returned promise should be handled with .catch:
app.get('/mongo', (req, res) => {
invoke().then(() => res.send('all good'))
.catch(err => console.log('invoke error:', err))
})

UnhandledPromiseRejectionWarning in Express App

I'm currently learning Javascript/Node.js/MEAN stack and I'm following an Express tutorial.
I get the following error:
(node:11524) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'close' of undefined
(node:11524) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
When I hit this route in my browser.
function router(nav) {
adminRouter.route('/')
.get((req, res) => {
const url = 'mongodb://localhost:27017';
const dbName = 'libraryApp';
(async function mongo() {
let client;
try {
client = await mongoClient.connect(url);
debug('Connected correctly to server');
const db = client.db(dbName);
const response = await db.collection('books').insertMany(books);
res.json(response);
} catch (err) {
debug(err.stack);
}
client.close();
}());
});
return adminRouter;
}
Could someone point out the issue and explain what the issue is please.
If this line rejects:
client = await mongoClient.connect(url);
Then, you go to your catch block and after that catch block, you call client.close(). But, client is undefined so client.close() will throw and you are not inside any sort of try/catch at that point. Since you're inside an async function, that throw will turn into a rejected promise which you have no .catch() to handle. Thus, you end up with an unhandled promise rejection.
You should be able to fix it like this:
function router(nav) {
adminRouter.route('/').get(async (req, res) => {
const url = 'mongodb://localhost:27017';
const dbName = 'libraryApp';
let client;
try {
client = await mongoClient.connect(url);
debug('Connected correctly to server');
const db = client.db(dbName);
const response = await db.collection('books').insertMany(books);
res.json(response);
} catch (err) {
debug(err.stack);
// make sure and send some response on errors
res.sendStatus(500);
}
if (client) {
client.close();
}
});
return adminRouter;
}
This makes several changes:
Add if (client) before calling client.close() to protect it from the case where `client never got set.
Make the whole .get() callback be async rather then using an IIFE (not required, just seems cleaner to me)
Send an error status and response in your catch statement so you are always sending an http response of some kind, even in error situations.
If you really wanted to be fail-safe, you could just add another try/catch:
function router(nav) {
adminRouter.route('/').get(async (req, res) => {
const url = 'mongodb://localhost:27017';
const dbName = 'libraryApp';
let client;
try {
client = await mongoClient.connect(url);
debug('Connected correctly to server');
const db = client.db(dbName);
const response = await db.collection('books').insertMany(books);
res.json(response);
} catch (err) {
debug(err.stack);
// make sure and send some response on errors
res.sendStatus(500);
}
try {
if (client) {
client.close();
}
} catch(e) {
console.log("unable to close database connection");
}
});
return adminRouter;
}

Properly terminate NodeJS Async Await

I wrote the following code to connect to MongoDB wrapped in a Promise, but as soon as it is connected, my NodeJS code is still running / not exit properly. May I know what is the proper way to return or terminate it?
function connectDB() {
return new Promise (resolve => {
MongoClient.connect(mongoUrl, function( err, db ) {
_db = db;
resolve(db);
});
})
}
(async function crawl() {
const db = await connectDB();
console.log('You are connected');
})()
This isn't really related to async/await, it also happens without. As #Torazaburo stated in the comments, the db driver maintains an open connection to the database, and this open socket (along with its eventhandlers) prevents node from quitting. Closing the connection helps:
function connectDB() {
return new Promise (resolve => {
MongoClient.connect(mongoUrl, function(err, db) {
if (err) reject(err);
else resolve(db);
});
});
}
(async function crawl() {
const db = await connectDB();
console.log('You are connected');
db.close();
console.log('You are no longer connected. Bye!');
})()
A promise have 2 paramaters: resolve and reject.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
You need to change your promise declaration:
return new Promise ((resolve, reject) => {
// ...
}
After that, add return statement to your promise:
return resolve(db)
Also, i suggest you to add an error log to your promise:
if (err) return reject(err)
And catch this error.
Good luck!

Can't get Node mssql to work properly

This is the way I'm using mssql at the moment but it gives sometimes errors:
JavaScript:
router.get('/academiejaren', (req, res) => {
sql.connect(dbconfig, function (err) {
var request = new sql.Request();
if (err) {
console.log(err);
return;
}
request.query("SELECT * FROM [Alg].[DefAJ];", function (err, recordset) {
if (err) {
console.log(err);
return;
}
else {
res.end(JSON.stringify(recordset));
}
});
request.query();
});
});
Error:
{ ConnectionError: Connection is closed.
at C:\Users\Milan\Documents\Octopus\Octopus 2.0\node_modules\mssql\lib\main.js:1569:17
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickCallback (internal/process/next_tick.js:104:9)
name: 'ConnectionError',
message: 'Connection is closed.',
code: 'ECONNCLOSED' }
(node:556) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ConnectionError: Connection is closed.
(node:556) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I'm using version 3.2.0 because I can't get the newest one, 4.0.2, to work... Any help or some good examples, because I can't figure out the documentation...
thank in advance!
EDIT
Updated on a small test project to 4.0.2. and I got it to work. Going to change my API to this update.
router.get('/academiejaren', (req, res) => {
(async function () {
try {
let pool = await sql.connect(config)
let result1 = await pool.request()
.query('SELECT * FROM [Alg].[DefAJ];')
res.send(JSON.stringify(result1.recordset));
} catch (err) {
res.send("CAUGHT ERROR academiejaren");
}
})()
sql.on('error', err => {
// ... error handler
})
});
Now I do have a small question left, what should I do with the catch and sql.on()? How should I handle error's?
router.get('/academiejaren', (req, res) => {
sql.connect(dbconfig, function (err) {
var request = new sql.Request();
if (err) {
console.log(err);
return;
}
request.query("SELECT * FROM [Alg].[DefAJ];", function (err, recordset) {
if (err) {
console.log(err);
return;
}
else {
res.send(JSON.stringify(recordset));
}
});
request.query();
});
});
you literally did res.end, end exits it, you want res.send
I do it a little bit different:
router.get('/', function(req, res, next) {
sql.connect(dbconfig).then(function() {
// Query
new sql.Request().query("Your query")
.then(function(recordset) {
//console.dir(recordset);
res.setHeader('Content-Type', 'application/json');
res.send( recordset );
}).catch(function(err) {
// ... query error checks
});
});
});
Now in your dbconfig make sure you got it like:
mssql://user:password#server/db

Categories

Resources