Take advantage of container re-use to improve the performance of your function.

Those contradictory statements make sense at scale.

When an AWS Lambda function completes (which means it terminates without unhandled exceptions, either with an error (also referred to as a failure) or a result (also referred to as a success)), the AWS Lambda service will automatically freeze its container and probably reuse it for a new invocation.

When an AWS Lambda function takes longer than the specified maximum execution time, the AWS Lambda service times it out by throwing an exception (unhandled by definition) and then manages it accordingly to some policies.

Given that AWS Lambda functions for a NodeJS runtime are NodeJS applications that, in general, add callbacks to the event loop, the AWS Lambda service will, by default, make sure that there is no pending work before considering the AWS Lambda function fully completed, independently from the fact that its callback was already called or not. To call the callback is, in fact, optional.

Unfortunately, if the AWS Lambda function somehow blocks the event loop (for example, a database connection which is being periodically polled), the AWS Lambda service won’t ever find the event loop empty and the AWS Lambda function will time out.

Conveniently, the AWS Lambda service calls the exports.handler function with a second argument set to the container context. In turn the context has a callbackWaitsForEmptyEventLoop property which can be set to false to signal to the AWS Lambda service that the callback call (in a way) marks the end of the AWS Lambda function.

AWS Lambda will freeze the process, any state data and the events in the NodeJS event loop (any remaining events in the event loop [will be] processed when the Lambda function is called next and if AWS Lambda chooses to use the frozen process).