There’s no place like ::1

AWS Lambda Functions in Go

| Comments

Update 1: Thanks @miksago for the much more robust node.js wrapper. I guess you can now see the reason why I wanted to avoid node :-)

I’m a big fan of AWS, and every year I get super excited about a new technology/service they release. Last year, I spent too much time marvelling about the simplicity and beauty of AWS Kinesis. And in the meantime, I’ve been applying the same principle on a smaller project I’m working on.

But this year I was stoked about AWS Lambda. AWS Lambda is a “compute service that runs your code in response to events and automatically manages the compute resources for you, making it easy to build applications that respond quickly to new information”. This is a perfect match for the event-driven and micro services way of thinking that I’ve been learning to love more and more.

But after skimming through the documentation, I’ve realised that the only supported runtime is Javascript (via Node.JS). I’m sure they will expand this support in the future, but I wanted to use it right now. Since in the meantime I’ve also been experimenting with Go lang, I wanted to find a way to run Go code on AWS Lambda right now.

Fortunately, it’s well known that you can statically cross compile your Go binary. This means I could generate a x86_64 Linux binary on my OS X system, and include it in the Lambda function distribution.

So first of all, cross compile your Go app:

test.golink
1
2
3
4
5
6
7
8
9
10
package main

import (
  "fmt"
  "os"
)

func main() {
  fmt.Printf("HELLO FROM GOLANG WITH ARGS %v", os.Args)
}
Cross compile go binary
1
$ GOOS=linux GOARCH=amd64 go build test.go

This will generate a test binary compatible with AWS servers. The only supported way of running AWS Lambda functions is still Node.JS. That means we still have to write a quick Javascript module to fork to our binary:

main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
var child_process = require('child_process');

exports.handler = function(event, context) {
  var proc = child_process.spawn('./test', [ JSON.stringify(event) ], { stdio: 'inherit' });

  proc.on('close', function(code) {
    if(code !== 0) {
      return context.done(new Error("Process exited with non-zero status code"));
    }

    context.done(null);
  });
}

Now you can follow AWS Lambda instructions, create a .zip file with both the Go binary and the JS file, upload and invoke it. At the end, you can see something like this on Cloudwatch:

Cloudwatch

So while you wait for AWS to add more runtimes, have fun with Go today :-)

Comments