Skip to content

Lambda Function - problems with connection to external MySQL

0

I coded a lambda function, using the AWS interface, and configured the Stages, API Gateway, ... My app only needs the API key, and no authorization..

When I run this code using the Lambda Function interface, the code runs well and a entry in the MySQL external database is inserted. However, when I run this function from my computer, the result is always

{"message": "Internal server error"}

However, sometimes, no entry in the MySQL database is created, and, sometimes the desired entry on the MySQL database is created. It seems that, the function quits before the query, as I saw in the logs.

My code is similar to:

import mysql from 'mysql';

var connection = mysql.createConnection({
host: 'external.not_aws.net',
user: '...',
password: '...',
database: 'my'
});

connection.connect();

export function handler(event, context)  {

    connection.query('INSERT INTO table_t (source,sourceIP,uid,date) VALUES (\'testing\', ?, UUID(), NOW())',  [event.requestContext.identity.sourceIp],
       function (error, results, fields) {
        if (error) {
            connection.destroy();
            throw error;
        } else {
            // connected!
            console.log(results);
            connection.end(/*function (err) {  }*/);

            return { 
                statusCode: 200,
                body: "Ok!"
            }
        }
    });
};

What is happening?

asked a month ago69 views
3 Answers
1

The issue you're experiencing is related to how Lambda handles asynchronous operations. Your Lambda function is returning before the database query completes because connection.query() is asynchronous, but your handler isn't waiting for it to finish.

When you call the function from your computer via API Gateway, Lambda may terminate the execution context before the database operation completes, which explains why sometimes entries are created and sometimes they aren't. The "Internal server error" message suggests the function is timing out or returning undefined.

To fix this, you need to make your handler properly handle the asynchronous database operation. Here are the key changes needed:

  1. Use callbacks or promises: Lambda needs to know when your asynchronous work is complete. You should either use the callback parameter that Lambda provides, or return a Promise.

  2. Don't return inside the callback: Your return statement inside the connection.query() callback doesn't actually return from the Lambda handler - it just returns from that inner function.

Here's how to fix your code:

export function handler(event, context, callback) {
connection.query(
'INSERT INTO table_t (source,sourceIP,uid,date) VALUES (\'testing\', ?, UUID(), NOW())',  
[event.requestContext.identity.sourceIp],
function (error, results, fields) {
if (error) {
connection.destroy();
callback(error);
} else {
console.log(results);
connection.end();
callback(null, { 
statusCode: 200,
body: "Ok!"
});
}
}
);
}

Alternatively, use promises with async/await for cleaner code:

export async function handler(event, context) {
return new Promise((resolve, reject) => {
connection.query(
'INSERT INTO table_t (source,sourceIP,uid,date) VALUES (\'testing\', ?, UUID(), NOW())',  
[event.requestContext.identity.sourceIp],
function (error, results, fields) {
if (error) {
connection.destroy();
reject(error);
} else {
console.log(results);
connection.end();
resolve({ 
statusCode: 200,
body: "Ok!"
});
}
}
);
});
}

The key is ensuring Lambda waits for your database operation to complete before the function exits.

answered a month ago
EXPERT
reviewed a month ago
  • Both options worked when I tested them for the first time. After that, the function returned error: "Cannot enqueue Query after invoking quit.". Is the connect action well placed?

  • In fact, the lambda function appears to be working sometimes. Mainly, when the calls to the function are a little bit spaced. Seems the code doesn't handle correctly the connection to MySQL.

0

Can you paste the whole code? You may be declaring the connection object outside of handler and destroying it inside. That would cause this issue. Here is how lambda handles the variables declared outside the handler:

When you declare variables, SDK clients, or database connections outside the handler function, Lambda treats them as part of the initialization phase (also called static initialization). Here's what happens:

First Invocation (Cold Start):

Lambda downloads your code and sets up the execution environment
Runs initialization code outside the handler (imports, global variables, SDK clients)
Executes the handler function
Freezes (not terminates) the execution environment after completion

Subsequent Invocations (Warm Start):

Lambda thaws the frozen execution environment
Reuses objects and connections declared outside the handler
Executes only the handler function
Freezes again after completion

You have two options: 1. Either create database connection inside the handler and end and destroy it inside. (this will cause some delay for each lambda execution. Also, if there are thousands of lambda invocations, it can affect the database performance)

  1. The second option is to leave the connection creating outside and do not end/destroy it inside the lambda handler. This would resolve your issue of subsequent runs without affecting the database performance.

Remember, even when the connection is created outside of the handler, it does not persist forever. It will get destroyed at sometime and recycled. Next Lambda run will not find the connection and reconnect.

AWS
answered a month ago
  • Please see my answer

0

I have changed my code, putting the connection creation inside the code. However, the same kind of errors continue to appear - see the error below. My code is:

import mysql from 'mysql';

var connection = mysql.createConnection({
host: ...,
user: ...,
password: ...,
database: "mysqldb"
});

export function handler(event, context, callback) {
    
    connection.connect(function (error) {
      if (error) {
        connection.destroy();
        callback(error);
      } else {

      connection.query(
        'INSERT INTO table_t (source,sourceIP,uid,date) VALUES (\'lambda\', ?, UUID(), NOW())',  
        [event.requestContext.identity.sourceIp],
       function (error, results, fields) {
           if (error) {
               connection.destroy();
               callback(error);
           } else {
               console.log(results);
               connection.end();
               callback(null, { 
               statusCode: 200,
               body: "Ok!"
               });
           }
       });
      }
    });
}

The error is: "errorType": "Error", "errorMessage": "Cannot enqueue Handshake after invoking quit.",

answered a month ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.