I am new to Node.js and I have the following code below:
const mysql = require('mysql');
async function insertNewRecord(record) {
const connectionUrl = 'mysql://root:mypassword#mydatabasehost:3306/mydb';
const pool = mysql.createPool(connectionUrl);
pool.on('connection', function (conn) {
console.log('*******on connection***********');
});
pool.on('error', function () {
console.log('****POOL CONNECTION ERROR***');
});
await pool.query('INSERT INTO users SET ?', record);
}
async function doProcess() {
try {
//construct record object
insertNewRecord(record)
} catch (error) {
console.log(error);
}
}
I purposely used the wrong database host name to see if the error would be caught and logged, but I saw no log. I was expecting to see POOL CONNECTION ERROR in the logs but it didn't show up. No error was caught either from the catch statement.
Am I doing something wrong? I did my own research and the pool.on lines you see in the codes is what I have tried to add, but doesn't seem to work. Am I doing error handling the correct way?
insertNewRecord(record) is an asynchronous function. If you don't use await with it node won't wait for the function to complete, and you won't see the error.
Related
It's not clear how to best trap errors using "mongoose.createConnection"
The Mogoose docs are pretty good at explaining how to trap an initial connection error when using "mongoose.connect" ... excerpt from docs., below:
mongoose.connect('mongodb://localhost:27017/test').
catch(error => handleError(error));
// Or:
try {
await mongoose.connect('mongodb://localhost:27017/test');
} catch (error) {
handleError(error);
}
However, in the case of "mongoose.createConnection" (neeed for more than one DB) ... this strategy does not seem to work. Here is what I've tried
const Db = mongoose.createConnection(dbUrl);
try {
await Db;
} catch (error) {
console.log(Error Connecting to DB");
}
which results in:
"SyntaxError: await is only valid in async functions and the top level bodies of modules"
Any pointers, please?
Thanks,
Tim.
Update following Anshu's post:
After making the changes, per Anshu, I then called the function
connectFunction()
and everything seemed OK, but only until the code reached the following line:
const Data = Db.model(`someCollection`, someSchema);
where it complained that "Db" is not defined. Presumably, because it is only scoped within the function? It feels like a chicken and egg situation. Any further guidance, please?
Update 11/18/22:
After making the following change:
async function connectFunction(){
try {
var db = await mongoose.createConnection(dbUrl);
} catch (error) {
console.log(Error Connecting to DB");
}
... same issue. I'm using VS Code and as a trivial observation, it colorizes variables, etc. In this case the variable "db" is "grayed out", i.e. it has recognized that something is wrong.
Update#2 11/18/22: I was able to make the "db is not defined error" go away once I realized I needed a return in the function. This is the latest code:
async function connectToBrandDb(url) {
try {
var Db = await mongoose.createConnection(url, {
keepAlive: true,
keepAliveInitialDelay: 300000,
serverSelectionTimeoutMS: 5000 });
}
catch (error) {
console.log(`Error Connecting To DB`);
}
return Db;
}
const brandDb = connectToBrandDb(dbUrl);
var Data = brandDb.model(`someCollection`, someSchema);
... and now looking at this from the terminal:
var Data = brandDb.model(`someCollection`, someSchema);
^
TypeError: brandDb.model is not a function
You should use async keyword before functions when you're trying to use await inside them. You cannot use await at the top (outside async function), so that's what the error is telling.
async function connectFunction() {
try {
const db = await mongoose.createConnection(dbUrl);
} catch (error) {
console.log("Error Connecting to DB");
}
}
What if I have a code like this:
var mysql = require('mysql');
var pool = mysql.createPool(...);
pool.getConnection(function(err, connection) {
if (err) throw err; // not connected!
// Use the connection
connection.query('SELECT something FROM sometable', 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.
});
});
The logic from initializing the pool until the entire getConnection process is located in an async function. So what happens is, when deployed in AWS, logs in getConnection are not logged because the handler finishes execution before the callback is processed. Due to this, the logs from line "if (err) throw err" is not seen in AWS cloudwatch logs.
Is there a workaround for this? I simply want to await the callback function in pool.getConnection
I did my research but all I found were specific implementations for specific scenarios, none quite similar to my scenario.
is it possible to await a callback function?
No, not with a plain callback that does not use promises.
await only does something useful when you're awaiting a promises. The connection.query() function call you show in your question does NOT use promises so there is no place for await with that function call as it is.
But, you can either wrap the connection.query() in a function that returns a promise (referred to as promisifying it) and create a new function that is promise-based.
Here's a look at how promisifying works. You don't show the overall context of your code. The promisifying would more typically be done at a more centralized location, but I've shown it here in the only context that you've shown:
const { promisify } = require('util');
async function someFunc() {
const pool = mysql.createPool(...);
pool.getConnectionP = promisify(pool.getConnection);
let connection;
try {
connection = await pool.getConnectionP();
connection.queryP = promisify(connection.query);
const results = await connection.queryP('SELECT something FROM sometable');
return results;
} catch(e) {
console.log(e);
// handle errors here
} finally {
if (connection) {
connection.release();
}
}
}
Or, your database already has a promise-interface and you can just use that (which would be my recommendation). See the mysql2/promise interface here where these functions are already converted to use promises and you can then use await with them.
I have a dynamo db table where I was able to insert data using node js via lambda. I am able to query from the console and I am also able to query using the cli. When using query with promise its erroring out with invoke error. Its not throwing any specific errors. IF I remove promise and run I can see that connection is successful to the db. I also tried ExpressionAttributeValues: {
":name": {"S":id}
},
even hard coding the value for id and same issue. What am I doing wrong??
import AWS from "aws-sdk"
const dyanamoDB = new AWS.DynamoDB.DocumentClient()
AWS.config.update({ region: "us-east-1" })
export const checkIFIDExist = async (id) => {
try {
const params = {
ProjectionExpression: "String1, String2",
IndexName: "String2",
KeyConditionExpression: "String2 = :name",
ExpressionAttributeValues: {
":name": id
},
TableName: 'my-table',
}
const data = await dynamoDB.query(params).promise()
console.log("Data:", data)
return "success"
}catch (err) {
throw new Error (`Failed query for ${id} `, err)
}
}
Error:
2022-08-16T20:24:09.210Z c2e0c093-2719-48b8-b0bb-4f38de3ac7b6 ERROR Invoke Error
{
"errorType": "Error",
"errorMessage": "Failed query for OE0K0I ",
"stack": [
"Error: Failed query for OE0K0I ",
" at checkIFStepFunctionIDExists (file:///var/task/src/dynamo-query.js:24:15)",
" at processTicksAndRejections (internal/process/task_queues.js:95:5)",
" at async Runtime.handler (file:///var/task/src/index.js:11:19)"
]
}
I basically deleted and trashed the project created new one and did the same stuff I had mentioned earlier in my post and instead of throwing error after catch statement console log it and I am getting the result I expected. I really couldn't tell what was I doing wrong before. #jarmond the error I posted above, I accidentally included a dependency while changing something and caused the error I provided. Thanks everyone for looking into the issue.
If the promise() function doesn't do what you expect it to do. It's worth noting, that you can actually also do the same thing with the standard Node.js promisify function.
import { DocumentClient } from "aws-sdk/clients/dynamodb";
import { promisify } from "util";
const docClient = new AWS.DynamoDB.DocumentClient()
...
const data = await promisify((cb) => docClient.query(params, cb))();
As #jarmod pointed out, there's probably something else going on though. I added some sidenotes to clarify some things that you may or may not already know.
Some sidenotes
Here are just some remarks which aren't entirely on topic but which can lead to confusion.
// don't do this, it doesn't do what you think it does.
throw new Error(`Failed query for ${id}`, err );
// this prints both a text and an object.
console.error(`Failed query for ${id}`, err);
// this throws just an error with a message
throw new Error(`Failed query for ${id}`);
// there is a 2nd argument which you can pass, which is an "options" parameter, which you can use to send a `cause` along.
throw new Error(`Failed query for ${id}`, { cause: err } );
PS:More details about it can be found it in the MDN documentation.
I haven't seen how you got it working without the promise, but if you did it like this, then it's not what you think.
try {
const params = { ... };
dynamoDB.query(params);
// this point is always reached
return "success"
}catch (err) {
// this point is never reached
}
Instead, without a promise, you would have to use a callback function.
const params = { ... };
dynamoDB.query(params, (err, data) => {
if(err) {
console.error(err);
return;
}
console.log("success", data);
});
I have created a saperate js file in node js and I am trying to connect to postgres sql using below code but it never worked. always promise is pending. code is not waiting at this line (await client.connect()). I Could not understand what the issue is. can any one please help me on this.
const pg = require('pg');
async function PostgresConnection(query,config) {
const client = new pg.Client(config);
await client.connect(); //not waiting for the connection to succeed and returning to caller and exit
const pgData = await client.query(query);
await client.end();
return pgData;
}
async function uploadDataToPostgres(config) {
var query="select * from firm_data";
await PostgresConnection(query, config);
}
module.exports = {
uploadDataToPostgres
}
I am trying to call above method from other page
function ProcessData()
{
var result = uploadDataToPostgres(config);
}
When you invoke an async function from outside an async function, you need to treat it as a Promise. Change your invoker function to look like this:
function ProcessData() {
uploadDataToPostgres(config)
.then(function success(result) {
/* do something useful with your result */
console.log(result)
})
.catch(function error(err) {
console.error('uploadDataToPostgres failure', err)
})
}
Your code, var result = uploadDataToPostgres(config), stashes a Promise object in result. But the code behind the promise (the code in your async function) doesn't run until you invoke .then() or .else() on it.
It's a bit confusing until you completely grasp the similarity between async functions and Promises: async functions are Promise functions with nice syntax.
It's possible your uploadDataToPostgres() function throws an error (failure to connect to the db?) and the .catch() will catch that.
The Problem:
I keep running into issues with typos in my SQL queries and the tedious driver isn't helping much. When there are errors, it does a fine job telling me the type of error and what went wrong, but the stack trace never contains any of my project files. This is making it difficult to debug, especially when I'm making multiple queries in the same function. I'm currently using the mssql library, but experienced the same problem using tedious directly. Plus, mssql isn't mentioned in the error's stack at all, so I figure it's not the problem.
What I've Tried:
Looking for issues on the tedious GitHub page
Added a conn.on('error') listener, which doesn't appear to do anything.
Added process.on() listeners for 'uncaughtException' and 'unhandledRejection'.
Moved the initialization of the ConnectionPool into it's own function to try and catch the error there. No luck.
Some Code:
Here's a barebones example of what I'm using to run the queries:
async function dbConnect() {
const conn = await new ConnectionPool(dbConfig).connect();
conn.on('error', error => {
console.error('*Connection Error:', error);
});
return conn;
}
async function runQuery() {
const conn = await dbConnect();
await conn.request().query(`SELECT Thing FROM Place`);
await conn.close();
}
runQuery()
.then(results => {
console.log(results);
process.exit(0);
})
.catch(error => {
console.error(error);
process.exit(1);
});
The Error:
Hopefully, this is something that's possible. If not, is there a different Node driver for SQL Server that someone's come up with?
Edit: Added an error listener on request
async function dbConnect() {
const conn = await new ConnectionPool(dbConfig).connect();
const request = new Request(conn);
conn.on('error', error => {
console.error('*Connection Error:', error);
});
request.on('error', error => {
console.error('*Request Error:', error);
});
return request;
}
async function runQuery() {
const request = await dbConnect();
await request.query(`SELECT Thing FROM Place`);
}