Binary As A Function

Nick Apperley
4 min readOct 25, 2020

Serverless can be a very confusing term that means different things to different people depending on who you talk to, which is a bit like Functional programming. Unfortunately there is no standard meaning used for Serverless that everyone agrees on. My favourite definition of Serverless that I have found was picked up from a presentation, which is the following:

  1. No management of server hosts or server processes
  2. Self auto-scale and auto-provision based on load
  3. Costs based on precise usage

If I were to define Serverless then this is the definition I would use:

A way to run a self contained program (Function) that can call another one where the server is handled by a platform, which manages the programs and automatically takes care of scaling/monitoring programs.

One implementation of this idea is to use a binary (native program) as a Function where all required libraries (dependencies) are statically compiled into the program itself. Input is handled by the main function in a program. Output is handled by the program printing messages. Errors are handled by the program printing error messages. This implementation will be explored by this blog post.

Unix Philosophy

The Unix philosophy acts as good way to describe Functions which are short programs (modular in nature), which do one thing well and can be composed to complete tasks. All Unix based operating systems (eg Linux) provide a standard way for programs to communicate with each other (IPC via pipes) that can be automated/scripted.

Pipes act as the glue that ties individual programs together. Each pipe is like a text file where multiple processes (programs) can read from it, and only a single process (program) can write to it. On a larger scale with multiple computers a technology like HTTP would be used to provide IPC between different programs running on different computers.

Serverless Platform

Kotlin Native was used to develop a proof of concept Serverless platform that can run a Function on demand. HTTP is used to enable communication with the platform, and forms the underpinnings to IPC. As a proof of concept (minimal implementation) many features are missing:

  • Monitoring Function resource usage
  • Providing a standard interface to pass input to a Function
  • Using containers to provide a constrained environment (limit CPU, RAM, storage etc) to run Functions
  • Termination of Functions that take too long to execute (using a execution timeout)
  • Capture all Function output/errors and include them in the HTTP response body

A single HTTP REST endpoint is exposed for calling a Function (eg localhost:10000/callFunc) with the first parameter (funcName) used to indicate the function to call. It is important to note that the Serverless Platform is programming language agnostic. The platform isn’t aware if the Function is written in Kotlin or not for example. Runtimes don’t need to be developed for each language unlike many other Serverless platforms which makes support a breeze.

Performance is reasonably decent with the Serverless Platform. Keep in mind no stress tests were performed, and Kotlin Native hasn’t been heavily optimised for performance yet. Also the libonion library has been statically linked which increases the binary size considerably. Below are some performance statistics:

  • Average RES memory usage: 416 KB
  • Debug Binary Size: 1484 KB
  • Release Binary Size: 464 KB

Function

Kotlin Native is used to develop a proof of concept Serverless Function, which is designed to be executed on demand by the Serverless Platform. Basically this means developing a native CLI program where all library dependencies are statically linked, which makes deployment reasonably straightforward. Input is handled by the main function in the program (if there is anything passed as arguments to the program). Output is handled by the println, and print functions (all of them send output to the stdout text stream). Errors are handled by the fprintf function (stderr used as the text stream).

Deployment of the Function is done in a single step by copying the Kotlin Native binary to a standard location used by the Serverless Platform (~/.serverless_platform/functions). Testing of a Function is very simple. Just test a Function like you would test a CLI program using Manual, and Unit testing techniques.

Performance is reasonably decent with the Function. Keep in mind Kotlin Native hasn’t been heavily optimised for performance yet. Below are some performance statistics:

  • Debug Binary Size: 1360 KB
  • Release Binary Size: 364 KB

Other Approaches

JetBrains have headed down the path of providing a framework for developing Serverless Functions using Kotlin called Kotless (uses the Apache 2 license). This framework is attempting to abstract away Serverless platforms, however the framework promotes closed Serverless platforms despite being Serverless platform agnostic. When developing a Serverless Function using Kotless a Kotliner is forced into using a supported microservices framework which isn’t designed for Serverless (eg Spring Boot). To make matters worse Kotless doesn’t support Kotlin Native, and isn’t likely to support Kotlin Native in the future given the current actions with the framework.

OpenFaaS is a open Serverless platform (uses the MIT license), and supports the use of different programming languages to develop Functions unlike Kotless. Both Kotlin JVM, and Kotlin Native can be used to develop Functions that run on the platform, however the Kotlin language isn’t officially supported although that might change in the near future. All Functions run in a Docker image. Kotlin Native programs can run in a Docker image however Docker isn’t very Kotlin Native friendly. When using Docker be prepared to deal with very long build/deploy times, manual cache management ( :( ), and a large amount of scripting using a build language that is Docker specific (extra context switching).

Conclusion

Although there isn’t a standard definition for Serverless its implementation can be simple, and is a combination of existing ideas/concepts which provide a different way to develop backend applications (aka ”old is new again”). Kotlin Native is capable of being used to develop both a Serverless platform, and Serverless Functions. It is a huge shame that the Kotlin team is overlooking Kotlin Native for Serverless (in favor of Kotlin JVM/JS) given its huge potential, and it is a key development platform that would allow Kotlin significant growth in the Serverless space, without having to use a different programming language like Go for example.

--

--