Skip to content

Make Feral more amenable to SnapStart optimization? #299

@cb372

Description

@cb372

A few weeks ago AWS announced SnapStart, a feature to improve cold-start performance for JVM Lambdas. A few lines of config to make my Lambdas magically faster? Yes please!

With SnapStart, Lambda initializes your function when you publish a function version. Lambda takes a Firecracker microVM snapshot of the memory and disk state of the initialized execution environment, encrypts the snapshot, and caches it for low-latency access. When you invoke the function version for the first time, and as the invocations scale up, Lambda resumes new execution environments from the cached snapshot instead of initializing them from scratch, improving startup latency.

My understanding of that paragraph is that they will "initialize" by calling the constructor on the handler class, but they won't invoke the Lambda, i.e. call the handler method.

Unfortunately (if I'm understanding Feral's code correctly) it appears that Feral Lambdas won't benefit much from this optimization. As I understand it, Feral does pretty much nothing at class initialization time. The resource defined in def init is acquired the first time the Lambda is invoked, and then memoized for reuse by subsequent invocations. So the SnapStart snapshot will capture the JVM startup and a bit of classloading, but none of the work performed while acquiring the init resource.

It would be nice if we could make everything that happens in IOSetup happen eagerly at class init time to take full advantage of SnapStart.

For now we can emulate this in user-land by eschewing def init and just doing a good old unsafeRunSync:

class MyLambda extends IOLambda.Simple[KinesisStreamEvent, INothing]:
  type Init = Unit

  private def buildAlgebra: IO[MyAlgebra[IO]] = ??? // the stuff that would usually go in `def init`

  private val algebra: MyAlgebra[IO] = buildAlgebra[IO].unsafeRunSync()

  override def apply(
      event: KinesisStreamEvent,
      context: Context[IO],
      init: Init
  ): IO[Option[INothing]] = algebra.process(event, context)

Disclaimer: I haven't done any benchmarking with SnapStart and Feral yet.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions