So great part of this is that this same code works on my development machine.
I'm trying to deploy it to the production server, and i'm getting this error:
Cannot call method release of undefined.
This works on my box, so why is that not working in production is what confuses me.
I downloaded the code with all the modules, then tried to do npm install, and still manually deploy express and mysql, but no luck.
The infringing line is:
connection.release();
If i rem that line, then it will just hang on anything trying to call connection.
The code:
process.env.TZ = 'UTC';
var express = require("express");
var mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit : 100, //important
host : 'localhost',
user : 'thedbuser',
password : 'thedbpass',
database : 'thedatabase',
debug : false,
timezone: 'utc'
});
var app = express();
function get_data(req,res) {
pool.getConnection(function(err,connection){
if (err) {
connection.release();
res.json({"code" : 100, "status" : "Error in connection database"});
return;
}
console.log('connected as id ' + connection.threadId);
var id = Number(req.param("id"));
connection.query("select * from thetable WHERE id = ?" , [id], function(err,rows){
connection.release();
if(!err) {
res.json(rows);
}
});
connection.on('error', function(err) {
res.json({"code" : 100, "status" : "Error in connection database"});
return;
});
});
}
app.get("/id",function(req,res){
get_data(req,res);
});
app.listen(3000);
pool.getConnection(function(err,connection){
if (err) {
connection.release();
res.json({"code" : 100, "status" : "Error in connection database"});
return;
}
So inside the if (err) block means there was an error. The node.js generic callback API semantic is when an err is passed to the callback function, the success/result variable is not guaranteed to also be provided. In this case, since there was an error getting a connection, no connection object is passed to the callback - because the error prevented the connection from happening correctly. Thus you can probably safely just delete the connection.release() line but if you know there is a case where both err and connection will both be passed (I suspect there is no such case), you could guard your call to connection.release() with an if (connection) block or a logical operator like connection && connection.release()
Related
I've created a simple mySQL database that I'm trying to access data from via an AWS Lambda function.
This is a version of the code that runs fine locally:
var mysql = require('mysql');
var config = require('./config.json');
var pool = mysql.createPool({
host : config.dbhost,
user : config.dbuser,
password : config.dbpassword,
database : config.dbname
});
pool.getConnection(function(err, connection) {
// Use the connection
connection.query("SELECT username FROM ClimbingDB.users WHERE email = 'testemail1'", function (error, results, fields) {
// And done with the connection.
connection.release();
// Handle error after the release.
if (error) throw error;
console.log(results);
process.exit();
});
});
This is that code converted to work with AWS Lambda:
var mysql = require('mysql');
var config = require('./config.json');
var pool = mysql.createPool({
host : config.dbhost,
user : config.dbuser,
password : config.dbpassword,
database : config.dbname
});
exports.handler = (event, context, callback) => {
//prevent timeout from waiting event loop
context.callbackWaitsForEmptyEventLoop = false;
pool.getConnection(function(err, connection) {
if (err) return callback(err)
// Use the connection
connection.query("SELECT username FROM ClimbingDB.users WHERE email = 'testemail1'", function (error, results, fields) {
// And done with the connection.
connection.release();
// Handle error after the release.
if (error) return callback(error);
else return callback(null,results);
});
});
};
Which times out with this error message:
{
"errorMessage": "2019-07-19T17:49:04.110Z 2f3e208c-62a6-4e90-b8ec-29398780a2a6 Task timed out after 3.00 seconds"
}
I'm not sure why it doesnt seem to be able to connect. I tried adding the function to a vpc and a security group that has access to RDB's, neither of which do anything. I'm not sure what I'm doing wrong here.
You will need:
The Amazon RDS instance in the same VPC as the AWS Lambda function
A security group on the Lambda function (Lambda-SG)
A security group on the RDS instance (DB-SG) that permits inbound connections on port 3306 from Lambda-SG
That is, DB-SG should specifically reference Lambda-SG (it will turn into a security group ID in the format sg-1234).
You might also want to increase the timeout of the Lambda function to give it a bit more time to run.
code as follows:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
port :"3306",
database :"mydb",
user : 'root',
password : '007007',
});
var isCon = true;
connection.connect(
function (err) {
console.log(isCon);
if (err) {
isCon=false;
console.error("error connecting :"+err);
return;
};
}
);
if(isCon){
connection.query('select * from tb_items', function(err, result) {
if (err) throw err;
console.log('The solution is: ', result);
console.log('The typeof solution is ',typeof(result));
debugger;
});
connection.end();
}
connection.connect(
function (err) {
console.log(isCon);
if (err) {
isCon=false;
console.error("error connecting :"+err);
return;
};
}
);
if(isCon){
connection.query('select * from tb_items', function(err, result) {
if (err) throw err;
console.log('The solution is: ', result);
console.log('The typeof solution is ',typeof(result));
debugger;
});
connection.end();
}
i just open()-->connect()-->query()-->end(),then did it again,but second time , there is a error : Error:Could not enqueue Handshake after invoking quiting .
question : maybe i can't reopen it after end().but i just wanna kwon ,if i end(),how can i reopen it?
no, you can't, just create another one. All state in the connection class only relevant for current connection, so having "reopenWithSameConfig" method is possible, but you should really do this from outside.
Also, you don't need to close connection on each query - just continue to reuse it without calling .end()
If you want multiple connections and automatic disposal of dead connections you should use Pool class.
One more note: your isCon check is incorrect, connection.query is called before connect() callback so it's always true. It's safe to just check error in query callback itself. If connection was not successful error is propagated to a queued command
I'm trying to write a simple server using nodejs and have the server ship back different queries and/or custom headers/responses based on the routes. However, in the getUsers() function the error keeps getting hit and printing the 'Error querying' to the console instead of printing the email rows. I know the server is connected fine, because I can return a query when I just use the db and return a query with createConnection only using the second example. Any help spotting the error is greatly appreciated. Thanks.
What I'm trying to get done:
var http = require('http');
var mysql = require('mysql');
var url = require('url');
var util = require('util');
var db = mysql.createConnection({
host : "*********",
user : "*********",
password : "*********",
port : '****',
database : '*********'
});
db.connect(function(err) {
console.log('connected');
if (err)
console.error('Error connecting to db' + err.stack);
});
function getUsers() {
db.query('SELECT * FROM users', function(err, rows, fields) {
if (err)
// changed console.error('Error querying');
console.error(err);
if (rows)
console.log('Rows not null');
for (var i in rows) {
console.log(rows[i].email)
}
});
}
var server = http.createServer(function(req, res) {
console.log(req.url);
if (req.url == '/signup') {
console.log("User signing up");
} else if (req.url == '/signin') {
console.log("User signing in");
} else if (req.url == '/new') {
console.log("User request new game");
getUsers();
}
//res.writeHead(200);
//res.end('Hello Http');
});
server.listen(3000);
// changed and commented out db.end();
What does work with querying the db:
var connection = mysql.createConnection({
host : "********",
user : "********",
password : "********",
port : '****',
database : '********'
});
connection.connect();
var queryString = 'SELECT * FROM users';
connection.query(queryString, function(err, rows, fields) {
if (err) throw err;
for (var i in rows) {
console.log('Users: ', rows[i].email);
}
});
connection.end();
The code has been updated with the changes, and the problem was I was closing the database. After changing the error logs as was suggested in the comments, this was the error received.
{ [Error: Cannot enqueue Query after invoking quit.] code: 'PROTOCOL_ENQUEUE_AFTER_QUIT', fatal: false }
I then commented out the
db.end()
and the queries were returned fine.
Thanks for the help.
So I started to try node.js this morning and was able to come-up with a http service that handles path requests and can connect to mysql with pooling for multiple transactions.
I am just having problems if ever I tried to make the password wrong, etc the node process quits unexpectedly.
var http = require("http");
var url = require("url");
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'localhost',
user : 'root',
password : 'root',
database : 'test'
});
...
var pathname = url.parse(request.url).pathname;
var url_parts = url.parse(request.url, true);
var query = url_parts.query;
...
var table = query.table;
var sql = "SELECT * FROM " + table + "";
...
pool.getConnection(function(err, connection) {
console.log(err);
connection.on('error', function(err) {
console.log(err.code);
});
// Use the connection
connection.query(sql, function(err, rows) {
if (err) throw err;
console.log(rows);
response.writeHead(200, {
"Content-Type" : "application/json"
});
response.write(JSON.stringify(rows, null, 0));
connection.end();
response.end();
});
console.log(connection.sql);
console.log(connection.query);
});
Appreciate any help on how can I make it not to QUIT! and just say the damn error.
Anyway, I used forever to make this node.js to never quit on me, in-cases of error.
You use throw err, but don t catch it anywhere, causing node a UncaughtException Error, closing the app.
I need a persistent MySQL connection for my Node web app. The problem is that this happens about a few times a day:
Error: Connection lost: The server closed the connection.
at Protocol.end (/var/www/n/node_modules/mysql/lib/protocol/Protocol.js:73:13)
at Socket.onend (stream.js:79:10)
at Socket.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:895:16
at process._tickCallback (node.js:415:13)
error: Forever detected script exited with code: 8
error: Forever restarting script for 2 time
info: socket.io started
Here is my connection code:
// Yes I know multipleStatements can be dangerous in the wrong hands.
var sql = mysql.createConnection({
host: 'localhost',
user: 'my_username',
password: 'my_password',
database: 'my_database',
multipleStatements: true
});
sql.connect();
function handleDisconnect(connection) {
connection.on('error', function(err) {
if (!err.fatal) {
return;
}
if (err.code !== 'PROTOCOL_CONNECTION_LOST') {
throw err;
}
console.log('Re-connecting lost connection: ' + err.stack);
sql = mysql.createConnection(connection.config);
handleDisconnect(sql);
sql.connect();
});
}
handleDisconnect(sql);
As you can see, the handleDisconnect code does not work..
Use the mysql connection pool. It will reconnect when a connection dies and you get the added benefit of being able to make multiple sql queries at the same time. If you don't use the database pool, your app will block database requests while waiting for currently running database requests to finish.
I usually define a database module where I keep my queries separate from my routes. It looks something like this...
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'example.org',
user : 'bob',
password : 'secret'
});
exports.getUsers = function(callback) {
pool.getConnection(function(err, connection) {
if(err) {
console.log(err);
callback(true);
return;
}
var sql = "SELECT id,name FROM users";
connection.query(sql, [], function(err, results) {
connection.release(); // always put connection back in pool after last query
if(err) {
console.log(err);
callback(true);
return;
}
callback(false, results);
});
});
});
I know this is super delayed, but I've written a solution to this that I think might be a bit more generic and usable. I had written an app entirely dependent on connection.query() and switching to a pool broke those calls.
Here's my solution:
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'localhost',
user : 'user',
password : 'secret',
database : 'test',
port : 3306
});
module.exports = {
query: function(){
var sql_args = [];
var args = [];
for(var i=0; i<arguments.length; i++){
args.push(arguments[i]);
}
var callback = args[args.length-1]; //last arg is callback
pool.getConnection(function(err, connection) {
if(err) {
console.log(err);
return callback(err);
}
if(args.length > 2){
sql_args = args[1];
}
connection.query(args[0], sql_args, function(err, results) {
connection.release(); // always put connection back in pool after last query
if(err){
console.log(err);
return callback(err);
}
callback(null, results);
});
});
}
};
This instantiates the pool once, then exports a method named query. Now, when connection.query() is called anywhere, it calls this method, which first grabs a connection from the pool, then passes the arguments to the connection. It has the added effect of grabbing the callback first, so it can callback any errors in grabbing a connection from the pool.
To use this, simply require it as module in place of mysql. Example:
var connection = require('../middleware/db');
function get_active_sessions(){
connection.query('Select * from `sessions` where `Active`=1 and Expires>?;', [~~(new Date()/1000)], function(err, results){
if(err){
console.log(err);
}
else{
console.log(results);
}
});
}
This looks just like the normal query, but actually opens a pool and grabs a connection from the pool in the background.
In response to #gladsocc question:
Is there a way to use pools without refactoring everything? I have
dozens of SQL queries in the app.
This is what I ended up building. It's a wrapper for the query function. It will grab the connection, do the query, then release the connection.
var pool = mysql.createPool(config.db);
exports.connection = {
query: function () {
var queryArgs = Array.prototype.slice.call(arguments),
events = [],
eventNameIndex = {};
pool.getConnection(function (err, conn) {
if (err) {
if (eventNameIndex.error) {
eventNameIndex.error();
}
}
if (conn) {
var q = conn.query.apply(conn, queryArgs);
q.on('end', function () {
conn.release();
});
events.forEach(function (args) {
q.on.apply(q, args);
});
}
});
return {
on: function (eventName, callback) {
events.push(Array.prototype.slice.call(arguments));
eventNameIndex[eventName] = callback;
return this;
}
};
}
};
And I use it like I would normally.
db.connection.query("SELECT * FROM `table` WHERE `id` = ? ", row_id)
.on('result', function (row) {
setData(row);
})
.on('error', function (err) {
callback({error: true, err: err});
});