2.3 Lambda: Event-Based Code Execution
Event-based code execution has become very common architecture with the proliferation of Node.js. However, to support it, you need to run a server. AWS Lambda eliminates this hassle and offers function execution in Node.js or Java so you don't have to worry about running an application server. We are going to create a Lambda function that compiles LESS stylesheets and stores the results in S3 (Simple Storage Service). Our custom Lambda function will also expose an API endpoint so it can be triggered externally.
1.Introduction3 lessons, 13:15
2.Amazon Web Services10 lessons, 1:17:39
3.Conclusion1 lesson, 01:25
2.3 Lambda: Event-Based Code Execution
Hi, welcome back to Explore Amazon Web Services. In this lesson we're going to look at Lambda, an event based code execution service. Event based code execution is a great thing. You'll save resources and costs by not having to run the service for a task that might only be triggered once in awhile, or have to actively pull from sources to determine if to trigger or not. Amazon Lambda provides you with an easy to use solution for this case. When you create a Lambda function, you have to select a blueprint to start off. And already, you can see the variety of event sources you can attach to the function. This ranges from a simple HTTP endpoint, to database triggers or topic subscriptions. We are going to start off with the hello-world blueprint to show the general structure of a lambda function. Except from choosing a name and description, you can also select the runtime. At the point of this recording, the options are either Node.js or Java. We are going to use the first one since it's faster to demonstrate and we can edit the code in line. Each Lambda function needs something to execute. This is typically called a handler, which takes the event data and the context. In this simple scenario, the data is just a travel script object containing three keys with values. The context is used to tell Lambda that the execution is complete. Very necessary with chronos code execution. You can either use succeed, fail, or done to signal a successful failed, or indeterminate execution. You will also need to give the function a role, which you can create here. I already created the basic execution role. So I'm going to choose that one. You can also choose memory requirements and the timeout. After which, the function gets killed. After creation, you can test the function with a sample event. The first time you use this, you need to set the event data. AWS provides you with sample data corresponding to each blueprint. Be aware when testing you will trigger all external services like it is a real execution of the function. Below are codes, we can see the results. It shows the returned value from context.succeed as well as the log output. When I want to change something in the code, I can do it right here. Let's change the values around a little bit and test again. Great, the values have changed. Now that we are down with hello-world, let's build a real function. I want to grade an HTTP micro service that compiles some less style code to CSS, uses auto prefixer to add vendor prefixes, minify the CSS, and save it to an S3 buckets. So a few steps the function has to do. As a blueprint, I'm going to choose the micro service HTTP endpoint, as it provides me with a way to easily generate the RP endpoints. We are going to choose a name and give a description. But I'm not going to use the end line edit at this time. I want to use node modules and I can do that. But I have to provide them packaged in an archive of the function. Before we are going to do this, let's finish the rest of the form. I want to create a new role that has access to S3. So I'm going to edit the policy and add the ability to use put object for the role. Now we are ready to develop our function. Let's start with a package file. I am going to choose a name and main execution file. And add some dependencies. Let's start with the development dependencies, since the Lambda function uses an MSNAMI that already provides hex's to the aws-sdk. I only need to put it as a development dependency. I also want to add grant, and grant AWS Lambda for testing and packaging. For actual dependencies, we are going to use less, postcss for prefixing and minifying, with autoprefix and cssnano. That can be used with plugins and also es6-promises. Lambda runs with a 0.10 note version and doesn't support promises yet, but cssnano needs them. With that done we can run npm install to install all packages. I'm creating the index.js file right now but before I write any code I want to setup my grunt file. It is a very simple configuration. I only need the tasks from AWS Lambda and set some options. The package provides free tasks, invoke package and deploy. I will be setting up all three of them but we're not going to use deploy in this lesson. But in a later one. For invoke, we need to specify our file name, which is index.js. For package, we don't need any special settings. And for deploy, we would need to set our function name on AWS or it's on. I also created a deploy task, that first packages the node modules and index files and then deploys its own AWS. Grunt tasks are set up, so let's get coding. First we need the es6-promises and qualify them to make them usable. Then we need the aws-sdk, less and postcss. I am then going to also intentiate the s3 service and specify an output bucket. Now onto the main function. First we are going to grab the last source and output file name from the event. Then we are rendering the last source into CSS. The callback gives an error and the output. If there is an error, we're going to fail. Otherwise we're going to invoke postcss with autoprefix and cssnano. And process the source. In the callback we are going to store the output in NS3 object in our bucket. And with the provided file name. Again, in the call back, if it fails, we are going to fail. Otherwise we are going to succeed. That's our function. So much work in under 30 lines of code. Great, now on to testing. I can test locally. But I have to create an event.json file to store our event data first. In a sample less code, I'm using the example code on the less homepage, which includes outdated webkit prefixes, that auto prefixer will remove. Now, before we are going to package the function, I'm going to create another file for packaging. The .npm ignore is specified to exclude certain files and folders from packaging. Those will be in this folder, which will be created by the packager. Since you don't want to include previous packages in your current one. The grunt file and the sample event data, let's switch to the shell and run grunt lamba_package to create the archive. As you can see the packaging fails. Our package json manifest is not extensive enough. I'm going to add a description, a version, and an alter to make it work. We can use the created zip archive to upload it to Lambda. Now we need to set up our API and plan for the API Gateway. Where we can set the API name, stage and end point. We can also specify the security settings, whether the API should be accessible by everyone or just for IAM users. After creating the function, we can already see the API endpoint that has been created for us. To test the function, we can copy our sample event from the json file and paste it into the web interface. After hitting test, we can see that the returned object has an ETag, which is a good indication that the function executed successfully, and does what it should. To view the compiled file in the browser, let me just give viewing permissions to the public. And now when we view the file, we can see that the code has been compiled, auto prefixer did its thing, and cssnano minimized it as well. Now onto API endpoint. I found that whenever I create such an endpoint, something is messed up with the role access rights, and API access doesn't work. So, we have to fix it manually. You can access your API gateway by clicking on it from the Lambda endpoints list. It will show you the different steps it´s going to do when an endpoint is requested. The Important part is the integration request which doesn't have access to execute the Lambda function. We can fix this easily though by changing it to a mock integration and then back to the Lambda function. It will then ask for permission to add execution rights through request. When hitting the API endpoint, we also have to send the content type header and set it to application json. I'm changing the file name to api.css to see whether it actually works. The ETag in the response shows us that the function run successfully. After setting the permissions again, we can view the api.css file in the browser. Now you can create micro services to run only when you need them to and expose them via an API using the API gateway. In the next lesson, I'm going to show you SQS, Amazon's message queue service. See you there.