cl-aws-lambda
cl-aws-lambda copied to clipboard
An implementation of the AWS lambda runtime for common lisp... :cry: lambdas.
#+TITLE: A CL Runtime for AWS Lambda
This is pretty alpha level software, but it seems to work fairly reliably and I'd welcome users to try it out. You may also be interested in using it in convert with the [[https://www.serverless.com/][serverless framework]], by means of my [[https://github.com/fisxoj/serverless-lisp][serverless-lisp]] plugin, which you can pull from npm.
-
How to use this
If that didn't deter you, read on!
** With the ASDF helper Hopefully the easy route, by defining your system, you can just define the code that needs to be run without caring much about the runtime implementation.
Define an asd file like this one, which marks your system as defining lambda functions. It will automatically cause your system to generate a binary named ~bootstrap~, which is what the aws runtime expects. It will also automatically depend on the ~cl-aws-lambda~ system.
#+BEGIN_SRC lisp (defsystem example-lambda :defsystem-depends-on ("cl-aws-lambda/asdf") :class :lambda-system :components ((:file "hello"))) #+END_SRC
Now, you can write regular common lisp however you'd like to, for example, this function that says hello when given a name:
#+BEGIN_SRC lisp (defpackage example-lambda (:use :cl) (:export #:hello))
(in-package :example-lambda)
(defun hello (event)
(let ((name (cdr (assoc "name" event :test #'string=))))
(if name
(format nil "Hello, ~a!" name)
(error "No name supplied!"))))
#+END_SRC
You should now be able to compile your binary by calling ~(asdf:make :example-lambda)~. The bootstrap binary produced is suitable for uploading to a lambda as a 'runtime provided' zip file. You can see an example of this in the ~example/~ directory.
** With the docker image [[https://quay.io/repository/fisxoj/cl-lambda-builder]]
You should be able to build your bootstrap / function.zip using the prebuilt docker image (the Dockerfile in this repo). By pointing your code at the =/work= directory and passing in your system name as ~LAMBDA_SYSTEM_NAME~, it will automagically build your lambdas for you. #+begin_src sh docker run --rm -it -v $PWD:/work:Z -e LAMBDA_SYSTEM_NAME="my-cool-function" quay.io/fisxoj/cl-aws-builder:latest podman run --rm -it -v $PWD:/work:Z -e LAMBDA_SYSTEM_NAME="my-cool-function" quay.io/fisxoj/cl-aws-builder:latest #+end_src
If you want to cache build artifacts between builds, you can check out the example in =example/Makefile=, which creates docker volumes for the build artifacts and quicklisp so they don't need to be fetched every build.
As always, it's recommended you pin the image to a version so you get consistent behavior in your builds. I don't have a strong enough idea of what stable means for this project to have versions beyond short hashes, but those are available as tags.
** Without the ASDF helper You can achieve the equivalent of the asdf helper class by providing these values to your system definition:
#+BEGIN_SRC lisp :build-operation "program-op" :build-pathname "bootstrap" :entry-point "cl-aws-lambda/runtime:main" #+END_SRC
** Writing handler functions Any function can handle lambda requests! Just define the handler as the lowercase name of the function so the runtime can find it (eg. ~example-lambda:hello~ in the example above).
Handler functions are currently functions of one argument that receive the json passed to the lambda decoded as an alist (to avoid keyword explosion of parsing it as a plist). The context is available as ~cl-aws-lambda/runtime-interface:context~ and you can investigate that package to find the class definition for that object.
- Common Errors
** ~/lib64/libc.so.6: version `GLIBC_2.28' not found~ A helpful hint from stassats on reddit sorted this one out:
#+BEGIN_QUOTE Can you try SBCL built after https://github.com/sbcl/sbcl/commit/6a78c5d72f14e65e0dd5be48efc00375e1df966e ? #+END_QUOTE
It seems like the minimum version of sbcl required is 1.4.14. Prior to that, it couldn't handle older versions of libc, like the one in the aws lambda runtime.
There is a dockerfile in the root directory that downloads a sufficiently recent sbcl to build its lambda that you can use as an example.