Things that you should know about new open source serverless platform: Fn

Was made by developers for developers because they care!

Intro

If you haven’t read my previous article “Demystifying Serverless Compute Manifesto”, i’d better go for it! Okay, Fn Project is a new star in serverless world open sourced by Oracle and made by the same team that started IronFunctions. Let’s be very skeptical here — is it a real serverless?

Demystifying Fn

At this particular moment i really want to see how it addresses all concepts of serverless (again, this is my own opinion):

  • functions are the unit of deployment and scaling — indeed, Fn defines two key resource types: app and route, where app is a placeholder for routes and each route represents a function.
  • underlying serverless infrastructure is not in control of users — Fn works on top of Docker and, so Fn is actually a FaaS (functions-as-a-service) and the user is capable of talking only to its API, but not underlying infrastructure.
  • function’s runtime is stateless — for each function Fn spins up a container, once the function is done the container is destroyed.
  • function scales with respect to number of requests. It can go hot (N requests to one function) or cold (one request — one function) — well, this is where Fn addresses cold and hot concepts in full, even more, hot mode allows to talk to a functions in two ways: HTTP and JSON.
  • implicitly fault-tolerant because runtime has predictable behaviour because it can be reproduced out of serverless platform — so, in Fn each functions runs inside its own containers, so users are able to test their function before deploying it, so the runtime is really predictable and fault-tolerant.
  • BYOR — bring your own runtime (serverless should operate containers as runtime for functions) — again, honest truth, Fn expects users to package their functions in container’s images and distribute them with help of public/private Docker registry.

So, Fn does really seem to be a serverless, huh?

Key concepts

Following questions are required to be answered in order to get clear view on Fn and see what it can offer.

How it works?

Fn allows its users to create an “app” and “route” to define a webhook URL as function’s trigger. On user’s request Fn does following:

  • composes function’s payload
  • builds STDIN/STDOUT pipe for a container
  • builds STDERR reader
  • starts a container with STDIN/STDOUT pipe writer/reader and STDERR reader attached
  • writes function’s payload to a pipe
  • awaits on pipe reader for function’s response and on STDERR reader for function’s logs, if it remains silent within defined (by user) timeout, function gets aborted
  • stops container
  • removes container

There are certain differences on how Fn acts depending on function’s format. This a very brief description of Fn’s internal processes, at least we’re here not for deep technical details.

What “app” is?

In order to create a function Fn will ask a user to create a placeholder for that function, so we call it an “app”, so the idea here is very simple — “serverless app” consists of number of functions, it means that each function should relate to at least one app.

But an “app” is not just a placeholder or reference implementation of “serverless app” concept, it also can hold config that would be available in each function related to particular app. App’s config can be a storage for secrets, DB connection URI, i.e. something that needs to be available in each function.

What “route” is?

Route defines a function itself, each route consists of function’s Docker image, call timeout, idle timeout (in-between-calls timeout), path (HTTP routing key to a function within particular app), format: cold (in Fn terms: default), hot (in Fn terms: HTTP, JSON), type (async or sync), config (similar to app config but this one has per-function availability), headers (HTTP headers to set to HTTP response from function).

Function’s format defines interaction contract/protocol between Fn and actual function, a user wouldn’t see almost any difference while working with function. The current implementation of Fn defines two types of protocols:

  • cold (i.e. default) — Fn reads HTTP request payload and writes it into function’s STDIN, waits for output from STDOUT
  • hot — at this moment there are two implementations: JSON (Fn reads HTTP request body, assembles JSON and writes it to function’s STDIN), HTTP (Fn dumps incoming HTTP request to function’s STDIN).

How sync/async function works?

Sync/async programming model is the most well-known technique in popular programming languages. Since Fn is not about programming languages but making function more agnostic to its runtime (you can run whatever you want as long as your runtime packaged into Docker image). So, Fn offers developers to choose whether they want to run their function asynchronously or synchronously.

Sync mode makes client and Fn await for function’s result in a real-time. Async mode makes a function to be scheduled for execution (in some languages, for instance in Python, it’s called “call soon”, delay assumed to be short, it equals to the timeframe that function’s call hangs in the queue of other async calls).

What is “format”?

Function’s format defines interaction protocol between Fn and function, but it also expects that function would be capable to read incoming data format from STDIN (no matter would that be JSON/HTTP for hot and, basically, text for cold). To make life a bit simpler Fn developers made few FDKs (function development kits) for the most popular programming languages like Go, Python, Java, NodeJS, etc.

What “call” is?

Call object represents a state of function’s call, it may be useful to figure out status, when it was scheduled, started and completed. Each call bound to an app and route.

What “log” is?

Log is everything that function would send to STDERR during. Each log bound to an app and call.

Something routes, calls, logs that you should be aware of!

In order to keep Fn’s datastore less polluted, it was decided to remove ALL calls and logs when a user attempts to delete this function.

Good API is documented API!

In order to make user experience while working with Fn API, we spend a certain amount of time to give developers freedom of tools to choose to talk to Fn API. Our HTTP API is documented with OpenAPI v2.0 standard (Swagger doc). Along with that Fn offers the tool to generate HTTP API client libraries for the variety of languages, few of them already there (Go, JS, Python, Elixir, Ruby binding). Why those binding matter? At this moment the easiest way to interact with Fn is to use CLI. But for the sake of building serverless apps it’s necessary to use this fn_{} libs because they provide sane and predictable API to talk to Fn.

Function development kits

So, what FDK is? If you ever build the serverless app that consists of dozen functions you may be noticed amount of code that is copied between functions to let them read from STDIN, these words imply to hot formats like JSON or HTTP. Comparing to microservices the only available transport streams between Fn and function are STDIN, STDOUT, STDERR. It means that each function should be capable of reading data from STDIN and parse it into sane form, it’s good to know if programming language of your choice has built-in capabilities to read HTTP request from anything that implements some kind of Reader interface (for instance, Go), where TCP socket and STDIN implementation have same roots, but for certain programming languages like Python, there’s nothing in stdlib that will to the same routine.

That’s why we tried to simplify the development process, reduce LOC necessary to build hot functions and we called that set of programming language-specific libraries the FDKs. For each programming languages, we’ve been developing with at this moment has its own FDK:

  • FDK-go — we love go, more example how to work with that FDK you can find here.
  • FDK-python — i’m personally responsible for this one, because i like Python, and i love to show to Python’s community that we’re good. HOWTOs and a lot examples you can find here.
  • FDK-java — Java was first officially supported FDK (was presented during OpenWorld).

More FDKs to come later, stay tuned or jump in, we love contribution!

So, why FDKs matter? Well, they let developers focus on their function and less think about the way Fn talks to function, basically, FDK hides protocol from users and lets them consume requests data. Also, FDK provides a call context entity — it has the necessary information about the particular call, like call ID, app name, request headers, function’s protocol, etc. One thing that developers should be aware of — protocol still matters, so it’s necessary to be careful with what you send back to Fn because protocols are not compatible, so you can’t read HTTP and write JSON or vice-versa.


Overall Fn looks quite interesting. Its beauty in its simplicity: code-push-deploy, the most powerful feature is its runtime — comparing to other FaaS solution having Docker’s container as the runtime for functions gives an ability to test our code before deploying it to Fn, and many more things like fn_* HTTP API bindings, FDKs. It looks like Fn was made by the developers for developers!

Key takeaways for those who want to know more about Fn:

  • HTTP webhooks is the only way to trigger functions
  • sequencing/chaining supported by Fn Flow
  • Docker container as the runtime
  • something new in serverless world — format (simple way to scale function)

If you want learn more about Fn i recommend to visit their blog at fnproject.io, watch their demos at YouTube, and join the community at Slack.