I recently posted that I was building a leaderboard for my ‘seisei’ app. I built the basic page and the DynamoDB tables but I needed a way to update the tables. The prior post discussed using EMR to update the scores on a periodic basis, but I want it updated more frequently. BTW, if you have no idea what i’m talking about, I’d suggest reviewing the previous post.
So, given that my templates are read directly from S3, and I’d like updates to the scores as quickly as feasible, I decided to use Lambda from AWS. Lambda is a stateless compute service that executes your Lambda Function in response to some sort of stimuli be it an event from S3 or an HTTP call via the API gateway.
This means I can have S3 notify me (or my Lambda that is) when something is accessed, and I can make a decision to update the score or not in Lambda, and then ask DynamoDB to do the data work.
That’s the gist of it.
Setting it up
Each individual step is documented very well by Amazon in the AWS documentation. I’ll leave the details to them. Here is my list of tasks I had to perform.
Create the DynamoDB Score table (done in previous post)
Turn on server logging on my S3 bucket - S3 allows me to setup access logging on my bucket that is used to serve out my templates (basic .json files). So, I turn on logging and specify another bucket (log-bucket).
Create my Lambda Function - I created my function right in the AWS console. It was easy and the console has a quick Lambda testing function that made it super quick for me to get it working.
Connect my Lambda to my S3 Log Bucket - on my log-bucket, add an event rule that fires an event on create (PUT) and choose Lambda -> My Lambda.
Watch it work - access some .json files in the first bucket, wait for the access log to hit and check the DynamoDb table for the result.
Running from the command line
Even though the AWS Lambda console is nice I quickly grew tired of it. I wanted to be able to run my lambda from the command line.
I wrote the following driver script and it served me well. The driver simply creates a sample event (ganked from AWS Lambda console), creates a fake context object and calls my Lambda. All I have to do is:
and my Lambda executes just as it would in the real Lambda environment on AWS.
Driver Code
The Lambda
Disclaimer - this is my first pass at this. I have not really refactored, nor even finished testing.
Testing My Lambda Function
In the AWS Console
Amazon has done pretty well with the Lambda console in my opinion. I was expecting a rather spartan experience but what I found was a Spartan that likes decorating. That is to say that there’s a built in editor (ace editor I think) and a basic testing facility that allows you to ‘Save and Test’ your script. It will execute the Lambda and output console messages right there in the console and the results of your function (via the succeed or done calls on the context).
They even provided a ‘sample’ event template function so that when you start to test, you can select the type of event (like an S3 put event) and then you can edit the event’s specifics. It makes for a pretty simple experience for getting up and running.
Via Jasmine
Testing in the console is all well and good but I wanted to be able to test my Lambdas like I test all my other code (via a command line build tool). There’s no shortage of testing blogs with node.js so i’ll spare you the nitty gritty details but I will touch on a few interesting points.
Mock ALL the Things!!!
The AWS SDK for JavaScript is loaded up as a CommonJS module just like any other node compatible module. Since you can load it up, you can mock it. I ultimately ended up using Sinon as my mocking framework. I started with Jasmine’s built in framework as it was the framework i’m most familiar with but ended up going with Sinon due to its sandbox functionality.
Jasmine Spec
Helper File
Difficulties
I had a few difficulties working with the Lambda service for the first time. I encountered most of my issues upon writing unit tests for my Lambda function. I haven’t done day to day JavaScript in a a little while, so I always seem to need to relearn the testing/mocking frameworks. However, that aside, I had some AWS specific issues during testing.
All in one file - while Lambda doesn’t require you to put your entire script in one file, it was the easiest for me to get off the ground. However, being in one file made it more difficult as I had to mock all the things as opposed to mocking out sub modules with nice interfaces.
No Libraries - Since i did this all in one file, I couldn’t add libraries like async which would have made much of this easier.
Force Reload of Modules - The sample code from Amazon has var aws = require('aws-sdk') and var s3 = new aws.S3() at the top of the file. To mock these out for each test anew, I had to force unload the modules or else my mocks/stubs would never be reset.
DynamoDb API - I feel like I spent a lot of time just figuring out how to do things with the DynamoDb API. Luckily the cycle time is very quick since I can run the lambda function from the command line via node.
End
This is not the best constructed post. I’m working to improve and there’s a lot of information to cover. If something isn’t working or you have a question, by all means contact me. There are several ways to contact me on the home page.
Comments