First, the use case: Lambda is great for infrequently-called or bursty services. Data processing pipelines, as an example, are a perfect function to be moved to Lambda. You don’t need to worry about provisioning capacity for big jobs, or paying for an idle server when not in use. Similarly, very small web services that don’t require on-disk operations or shared resources can run (or sleep!) happily on Lambda.
Second, the choice between JVM Clojure and ClojureScript: Even with AOT compilation, the JVM warmup penalty compared to Node.js is huge. Once invoked, Lambda will keep your image warm for an indeterminate (about five minutes, in my experience) period of time, but after that, the next invocation will once again require sometimes something like 15 seconds to get going again. If your function is doing something like chewing through big amounts of data and throwing the results into S3 or a database, that’s not a problem. If you need to quickly respond to a web request, it is.
So even though JVM Clojure is easier to write and reliably deploy (just package up a .jar and upload it), we’re going to be writing a ClojureScript web service here. To demonstrate how to integrate Node libraries with ClojureScript, the service will take a JSON payload via post and return it signed as a JSON Web Token. We’ll use cljs-lambda to get started:
$ lein new cljs-lamba jwtify Generating fresh 'lein new' cljs-lambda project. $ cd jwtify/
Now we’ve got a skeleton of a ClojureScript Lambda project we can flesh out to
suit our purposes. We’ll need to add two dependencies that we’re going to use to
[bidi "2.1.1"] in
lein deps now will pull in both of
those, using npm to install the jsonwebtoken
src/jwtify/core.cljs file generated by
lein cljs-lambda comes with a
promise-based demonstration, but we don’t need it. We’ll be using simple
core.async channels to handle the asynchronous pattern Node.js requires, so
let’s replace all of that and start new:
This is the minimal amount of code that will get us a an entry point into a function from Amazon’s API Gateway and return a status and a JSON payload.
To test it out, we can create a
dev/repl.clj file that looks like:
rlwrap lein trampoline run -m clojure.main dev/repl.clj to get
yourself into a ClojureScript/Node.js REPL, and try:
What we’re doing with
channel is locally simulating a Lambda event that our
function will eventually receive in real life and putting the result on a
To recap: We’ve set up a ClojureScript/Node.js environment with the
cljs-lambda library that knows how to interpret AWS Lambda events and
return responses in the esoteric format Lambda and the API Gateway expect.
In part two,
bidi to set up routes and response handlers for our
web service, and
jsonwebtoken to generate our JWT payloads. In part three,
we’ll see how to put it all together and deploy it to The Cloud.