With a new post on its blog, the Swift team have recently announced the creation of a custom runtime for AWS Lambda allowing developers to write serverless functions in Swift.
Serverless functions are an extremely easy way to implement server-side logic and to deploy it in a 100% managed, and particularly cheap, environment.
But, why Swift? Beside being the most familiar language for developers targeting Apple platforms, the very nature of the language makes it very well suited in a serverless environment. As the announcement article says:
When using serverless functions, attention must be given to resource utilization as it directly impacts the costs of the system. This is where Swift shines! With its low memory footprint, deterministic performance, and quick start time, Swift is a fantastic match for the serverless functions architecture.
Time to experiment!
According to the article, deploying a new AWS Lambda function seems quite an easy task. But, is it really the case? We couldn’t wait testing and, as a proof of evidence, we made a short video about this, so you can judge by yourself!
(Too Long; Didn’t Watch: it’s very easy – provided that you already have some basic concepts on AWS).
The step-by-step tutorial on macOS
Let’s get through the video step-by-step. There’s quite a few number of actions involved here:
Prerequisites
- Install Docker Desktop for Mac: this is needed to create a binary executable compatible with the Amazon Linux OS, which is the environment the Lambda will run on, when deployed.
- Create a AWS Account (if you don’t have one yet)
- Install & Configure the AWS Command Line Tool 3a. 3b.
Creating and deploying a Swift AWS Lambda function
- From within Xcode, create a new Swift Library Project, named (for instance) « MyLambda »
- Modify Package.swift:
- Add
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "0.1.0")
to the package dependencies - Add
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime")
to the target dependencies
- Add
- Code Sources/MyLambda/main.swiftA function can be as simple as:
import AWSLambdaRuntime struct Request: Codable { let name: String } struct Response: Codable { let message: String } Lambda.run { (context, request: Request, callback) in callback(.success(Response(message: "Ahoy, \(request.name)"))) }
- Create a Dockerfile. This is needed because the actual compilation for the AWS Lambda machine instances need to be performed in a compatible environment:
# The scripts will run the compiler on Amazon Linux, in order to produce # an executable binary compatible with AWS Lambda. FROM swiftlang/swift:nightly-master-amazonlinux2 RUN yum -y install zip
- Run docker and AWS commands to build and deploy. For this, we built a small gist repository containing some scripts to avoid copy-and-pasting boring bash commands:
git clone scripts
To produce the binary code, via Docker, let’s run:
# The build-and-package.sh is a modification of the tool provided by Apple on the # repository ./scripts/build-and-package.sh MyLambda
And to deploy the binary to AWS:
# How does this work? Feel free to read the comments here: # ./scripts/aws-deploy.sh
Performance
Before we wrap up, let’s take a look at the performances to verify the statement on the Swift blog is correct.
In our (albeit extremely simple) test scenario, and with no optimisation, the cold startup time (Init Duration) of the function was consistently around 140-145ms, with a median execution time of ~1ms and 50MB of used memory.
By comparison, the same use case written in vanilla JavaScript on Node.js 12, had a better startup time (134ms), around the same median execution time (at ~1.03ms) but a 22% worse memory footprint at 64MB.
These elements are of major importance in AWS Lambda, as its pricing mainly depends on execution time and used memory. In other words – once again, in our use case – the Swift implementation of the function could provide significant long-term savings in a production environment.
Truth be told, this is without considering the risk of memory leaks that Swift developers could incur into, which is somewhat greater in comparison to JavaScript.
And that’s all!
With a prior knowledge of the AWS environment it’s quite fast to go through all the steps, prerequisites included. The experience, on the Swift side, is pretty much hassle-free.
We’re not entirely convinced about 2020 being the year of Swift on the Server, as Tim Condon said in a recent blog post, but the Swift runtime for AWS Lambdas is an important step in the right direction.