/plambda

Wrapper for Play! apps to run them in AWS Lambda

Primary LanguageScala

Plaλ!

download

This is a somewhat comedic attempt to make Play! apps work in AWS Lambda. It actually succeeds surprisingly well (so long as your expectations are appropriately low).

Getting started

  1. Look at yourself in the mirror and consider whether running your app in AWS Lambda is something you’ll be able to live with. Plaλ comes with no warranty and I will provide no counselling for this life choice.

  2. Add the Plaλ library to your Play 2.5 project and also include Play’s test framework (2.5.x) and the AWS S3 client (1.11.x) - the wrapper relies on these being present, but does not provide them. Add something like this to your build.sbt:

    resolvers += "Plambda Releases" at "https://dl.bintray.com/sihil/plambda"
    libraryDependencies ++= Seq(
      "net.sihil" %% "plambda" % "0.0.1",
      "com.amazonaws" % "aws-java-sdk-s3" % "1.11.48",
      "com.amazonaws" % "aws-java-sdk-lambda" % "1.11.48",
      component("play-test")
    )
  3. Configure your application to dist a zip file containing all the libraries etc. You need a zip file that contains all your libraries in lib/. Adding this to the settings for your play project in your SBT configuration should work:

    topLevelDirectory in Universal := None
  4. Run dist - this should now create you a zip file suitable for uploading to AWS Lambda.

  5. Create a CloudFormation stack. I suggest you start with the example template provided and customise as appropriate to grant your application any permissions it needs (note that prior to bringing this up you’ll need to upload an initial copy of your lambda into the S3 bucket specified).

Optimisations

  • Move any static assets from your application to something else. Serving static assets from Lambda has significant performance implications - it will be much better to shift these onto a CDN or similar.

  • If you can avoid using a VPC then don’t - AWS say that this can have a notable impact on the latency of a cold start.

Known limitations? Plenty…​

  • The API Gateway to Proxy Lambda integration can’t cope with setting multiple cookies in one response. Plambda tries to deal with them by internal magic but only if they are set on a 3XX redirect response. If multiple cookies are set on a 2XX response then only one will be set and the others will be dropped (logging that this happened).

  • Likewise, multiple identical query parameters are not supported, again due to a limitation in AWS.

  • API Gateway has the opinion that only UTF8 data is value and forces all data to or from a lambda into UTF-8. This means that any non-UTF8 responses could become corrupted (note that this is unusual for a Play! app which is UTF-8 throughout by default). Plaλ tries hard to return binary data to users correctly by funnelling such content via an S3 bucket when a returned content type is not on an internal UTF-8 safe whitelist.

  • Performance is somewhat poor when the application has not been used recently, due to the start up time of Lambda functions. This is somewhat mitigated by using 1.5Gb of RAM (as larger amounts of memory also means more CPU power). In addition a five minute "ping" is supported by Plambda and used in the CloudFormation which helps to keep the function luke warm at minimal cost, significantly reducing latency for infrequently used apps.

  • WebSockets outright won’t work and never will with the current design of Lambda.

Future work

  • Try using it with more projects

  • Build an asset interceptor that attempts to automatically re-route known static assets to a static location such as an S3 bucket (seems that this is best done by creating a custom RouteGenerator to replace the standard Play generator).