Feral is published for Scala 2.13 and 3.2+ with artifacts for both JVM and Scala.js 1.13+.
// Scala.js setup addSbtPlugin("org.typelevel" %% "sbt-feral-lambda" % "0.2.2") // in plugins.sbt enablePlugins(LambdaJSPlugin) // in build.sbt // JVM setup libraryDependencies += "org.typelevel" %% "feral-lambda" % "0.2.2" // Optional, specialized integrations, available for both JS and JVM libraryDependencies += "org.typelevel" %%% "feral-lambda-http4s" % "0.2.2" libraryDependencies += "org.typelevel" %%% "feral-lambda-cloudformation-custom-resource" % "0.2.2"
Next, implement your Lambda. Please refer to the examples for a tutorial.
There are several options to deploy your Lambda. For example you can use the Lambda console, the SAM CLI, or the serverless framework.
To deploy a Scala.js Lambda, you will need to know the following:
- The runtime for your Lambda is Node.js 18.
- The handler for your Lambda is
indexrefers to the
yourLambdaNameis the name of the Scala
objectyou created that extends from
sbt npmPackageto package your Lambda for deployment. Note that you can currently only have one Lambda per sbt (sub-)project. If you have multiple, you will need to select the one to deploy using
Compile / mainClass := Some("my.lambda.handler").
- For the tooling of your choice, follow their instructions for deploying a Node.js Lambda using the contents of the
As the feral project develops, one of the goals is to provide an sbt plugin that simplifies and automates the deployment process. If this appeals to you, please contribute feature requests, ideas, and/or code!
Why go feral?
There are a lot of reasons for this, cold-start being one of them, but more generally it's important to remember what the JVM is and is not good at. In particular, the JVM excels at long-lived multithreaded applications which are relatively memory-heavy and rely on medium-lifespan heap allocations. So in other words, persistent microservices.
Serverless functions are, by definition, not this. They are not persistent, they are (generally) single-threaded, and they need to start very quickly with minimal warming. They do often apply moderate-to-significant heap pressure, but this factor is more than outweighed by the others.
Cats Effect takes this a step further by establishing semantics for asynchronous programming (aka laws) and guaranteeing them across the JVM and JS. In fact, the initial testing of these semantics on Scala.js revealed a fairness issue that culminated in the deprecation of the default global
ExecutionContextin Scala.js. As a replacement, the
MacrotaskExecutorproject was extracted from Cats Effect and is now the official recommendation for all Scala.js applications. Cats Effect
IOis specifically optimized to take advantage of the
MacrotaskExecutor's fairness properties while maximizing throughput and performance.
Your favorite Typelevel libraries are already designed for Scala.js.
In practice, this means you can directly transfer your knowledge and experience writing Scala for the JVM to writing Scala.js and in many cases share code with your JVM applications. The following libraries offer identical APIs across the JVM and JS platforms:
- Cats and Cats Effect for purely functional, asynchronous programming
- fs2 and fs2-io, with support for TCP, UDP, and TLS
- http4s, including DSLs, server/client middlewares, and ember
- natchez and natchez-http4s for tracing
- skunk for Postgres/Redshift and rediculous for Redis
- circe, scodec and scodec-bits for encoders/decoders
- smithy4s for AWS clients
- and more ...