AWS Lambda with Scala and GraalVM
--
In Scanye we’ve been developing a monolith, containerized Scala web application running on AWS ECS, that has served us well. But as we’ve been growing fast for a while now (and so has been our traffic), we’ve decided to split the monolith and finally embrace AWS Lambda Functions.
As a starting exercise, we’ve decided to go with something simple: a
cron function to regularly clean old and expired data from the database.
Such a function does not need to receive any events or integrate with API Gateway. All we need is to create a DAO object, run a single method and log the result.
There are two reasonable ways of running Scala code on AWS Lambda. One is to produce a JAR file and run it in a usual manner using Amazon’s Java runtime. The other one is to use GraalVM’s ahead of time compilation and build a standalone binary.
AWS Lambda does not support Scala directly, so running Scala code in Java runtime requires dealing with some “Javaisms” at the points of entry and exit. The built-in Lambda serializer doesn’t understand native Scala types,
so we have to map Java code into Scala, which is a pity. Moreover, as utilities of this kind are executed rarely, one at a time and run for just a few seconds, one wouldn’t even begin to feel any efficiency boost achieved from just in time optimizations.
Therefore, building a binary seems to be a better approach, since we can:
- create an executable that is small (and thus lowers startup latency and unnecessary bandwidth usage), letting us reduce a 100MB JAR file to tens or so MB,
- make the code simpler (no Java(ish) code to handle the Lambda interface),
- make it run quickly (as no class loading and rather complex JVM initialization and warm up is necessary),
- make it use as little memory as possible (again, no VM overhead).
Building a lambda
To start with, I created a new package with this simple program: