The short answer is that there is no such event to know when the container is stopped.
UPDATE: I've not used this library, but https://www.npmjs.com/package/serverless-mysql appears to try to solve just this problem.
PREVIOUS LONG ANSWER:
The medium answer: after speaking with someone at AWS about this I now believe you should scope database connections at the module level so they are reused as long as the container exists. When your container is destroyed the connection will be destroyed at that point.
Original answer:
This question touches on some rather complicated issues to consider with AWS Lambda functions, mainly because of the possibility of considering connection pooling or long-lived connections to your database. To start with, Lambda functions in Node.js execute as a single, exported Node.js function with this signature (as you probably know):
exports.handler = (event, context, callback) => {
// TODO implement
callback(null, 'Hello from Lambda');
};
The cleanest and simplest way to handle database connections is to create and destroy them with every single function call. In this scenario, a database connection would be created at the beginning of your function and destroyed before your final callback is called. Something like this:
const mysql = require('mysql');
exports.handler = (event, context, callback) => {
let connection = mysql.createConnection({
host : 'localhost',
user : 'me',
password : 'secret',
database : 'my_db'
});
connection.connect();
connection.query('SELECT 1 + 1 AS solution', (error, results, fields) => {
if (error) {
connection.end();
callback(error);
}
else {
let retval = results[0].solution;
connection.end();
console.log('The solution is: ', retval);
callback(null, retval);
}
});
};
NOTE: I haven't tested that code. I'm just providing an example for discussion.
I've also seen conversations like this one discussing the possibility of placing your connection outside the main function body:
const mysql = require('mysql');
let connection = mysql.createConnection({
host : 'localhost',
user : 'me',
password : 'secret',
database : 'my_db'
});
connection.connect();
exports.handler = (event, context, callback) => {
// NOTE: should check if the connection is open first here
connection.query('SELECT 1 + 1 AS solution', (error, results, fields) => {
if (error) {
callback(error);
}
else {
let retval = results[0].solution;
console.log('The solution is: ', retval);
callback(null, retval);
}
});
};
The theory here is this: because AWS Lambda will try to reuse an existing container after the first call to your function, the next function call will already have a database connection open. The example above should probably check the existence of an open connection before using it, but you get the idea.
The problem of course is that this leaves your connection open indefinitely. I'm not a fan of this approach but depending on your specific circumstances this might work. You could also introduce a connection pool into that scenario. But regardless, you have no event in this case to cleanly destroy a connection or pool. The container process hosting your function would itself be killed. So you'd have to rely on your database killing the connection from it's end at some point.
I could be wrong about some of those details, but I believe at a high level that is what you're looking at. Hope that helps!