Spotlight
AWS Lambda Functions: Return Response and Continue Executing
A how-to guide using the Node.js Lambda runtime.
Mon, 07 Mar 2016
Often with new technology some of the primary benefits are realized when you reevaluate how you approach a problem. AWS Lambda and event driven computing is no exception.
I’m going to walk you through one of the more exciting types of approaches we have started using recently, which we call the “fanout” pattern. If you are familiar with recursion, the core concepts of Lambda fanout should be somewhat familiar to you.
At the beginning of any fanout is a single Lambda function that receives the initial request or event. From there, events are fired off to other instances of Lambda functions. The secondary functions could call tertiary functions and so on and so forth. The events propagate (fanout) until the workload is manageable in some reasonable time or CPU constraints. In many situations, the responses then bubble back up to the initial function, and then the final response is passed back to the initial requester.
One important thing to consider is that every single instantiation of a Lambda function gets its own network, memory and CPU. That means that each additional Lambda call that happens as part of your fanout has as many resources as all the others. There is no risk of processes starving each other out, so fire away!
If you have potential batch processing jobs, or something that you would traditionally either background or push off to to a queue / worker pool, this may be something worth considering.
Let’s consider a common use case discussed at re:Invent that applies to multiple industries. The challenge is to to resize tens or hundreds of images to some arbitrary size and get them back to the client as quickly as possible. With a properly written and optimized fanout pattern-based request / response model, you can see how resizing large batches of images on the fly, while maintaining sub-second response times, is easily accomplished.
Other use cases include:
When considering the fanout pattern, carefully evaluate the potential performance cost of spinning up new instantiations of Lambda functions (a single instantiation can be reused over and over, but will only stay warm for a few minutes) of lambda functions, and network request overhead. For example, in our image resizing, we do not use Lambda fanout for a single image resize because the potential performance cost is significant. For 10 or 100+ images, it is absolutely worth fanning out.
If you are using AWS Lambda with NodeJS specifically, there is a NodeJS default configuration that limits open sockets to 5. With the fanout pattern, 5 connections is trivial, and will quickly become a bottleneck. Here is the fix, as part of your instantiation of the AWS object:
var agent = new https.Agent();
agent.maxSockets = Infinity;
var AWS = require('aws-sdk');
AWS.config.httpOptions = { agent: agent }
To keep your lambda containers warm you could implement a schedule lambda that invokes as many instances of your function as you need to have warm and ready to go. Just provide an early exit in your code so you don’t rack up the AWS spend.
exports.handler = function(event, context) {
if (event.heartbeat) return context.done(null, "Heartbeat")
// the rest of your code here
}
Now get out there and fanout!
A how-to guide using the Node.js Lambda runtime.