At JavaOne 2017 this year, Oracle announced and open-sourced its own serverless paltform called Fn Project. In this article, we will have a first look on Fn Project and what it offers to developers.
According to the project homepage, Fn is a container native serverless platform for running functions. Maybe it is a bit too far fetched to call it a platform, however, it is a suite of tools, programs and libraries that allow for writing, testing and deploying functions on a FaaS (function-as-a-serivce) platform like AWS Lamda. You’re not forced to do so, you can also run the functions locally or in any other public or private cloud (so you can run them basically everywhere).
Although coming from Oracle, Fn does not only support Java but basically every programming language according to the documentation. The
fn init command however shows the following platforms/file extensions:
.js, .rb, .py, .java, .go, .php, .rs, .cs, .fs.
It’s important to understand that the basic building block of Fn are containers. Every function defined is written and tested as a separate function and packaged in its own container. To be more precise, currently Docker is the primary technology for packaging and distribution (to Docker registries). However, according to Fn’s github FAQ, the tool is build in a way so that it abstracts the actual container technology.
The First Function
Let’s have a look how functions can be defined. One part of Fn is the command line tool (CLI). In order to install it locally you can run
or you might instead want to download the binary distribution
Once the script or binary is installed, you can run
This will fire up a local server including an embedded database and message queue. Imagine this server as a conceptual container routing to your functions. It also provides a function API for querying meta-data and executing other operations on behalf of the registered functions. The server is again a Docker container and it uses the image “fnproject/functions” for running the function container. Once started, you can access Fn functions under
There is also a Docker image providing a graphical user interface for Fn, you can launch it with
It provides a dashboard and a link to the Swagger Fn Function API documentation.
Now we add our first function in Java and create the initial project structure with
We specify the runtime type directly here, we could have also created our function first to let Fn determine the runtime type automatically, however, for runtime Java it is better to specify the runtime directly.
The resulting project structure is
Fn uses Maven in the background for packaging the function, so that’s why the directory layout should look familiar to readers of this blog.
That’s how the generated
HelloFunction.java looks like:
When we run this function with
fn run, we get the following output
As you can see, it builds a Docker image from our function and directly runs it as a container, resulting in the
Hello, world! output in the last line. What we just saw is the basic concept of Fn. Package a function into a container and whenever this function is requested, run the container to execute the function. As we said in the beginning, the container is really the basic building block.
func.yaml contains the function configuration. You can see that
HelloFunction::handleRequest is defined as an entry point, together with the version string and the runtime type:
There is more to configure than that but for our first example this should be okay.
fn run just executed our function, however, that was only for testing the function output. Let us deploy the function to our function container running on
localhost:8080. Deploying a function register the function in the function container and creates a so-called route to the newly registered function. After this route is created, the function container news about the function and it its execution can be requested via a REST call.
Before we can do that, we have to set the
FN_REGISTRY environment variable. It is needed because Fn will push the created image to the Docker registry (as a default, to the Docker hub). If you didn’t do a
docker login before, you might want to do that before proceeding with the next commands:
When we deploy our function, we have to add the function to an application (here
projectfn). In Fn, applications basically bundle a set of functions.
After our newly created application has been created and the function has been deployed, we can list our routes to see the actual REST URL for our function:
New we can call our function with
Maybe you saw that our example function
HelloFunction also took an input argument. We can
echo this to our
As stated above, the function container comes with a function API so that REST calls can also be used to gather meta-data and execute operations about/on the available applications and functions.
Fn Java FDK
When using Fn together with Java, you can make use of the Function Development Kit (FDK). As a matter of fact, we already made use of the FDK in our previous example.
In our function
HelloFunction we had a method
handleRequest(String) which got a
String argument. Normally, incoming data is coming from STDIN. With the FDK however, we got a nice argument without having to read with a buffered input, this functionality is called simple data binding. FDK does not only support
byte input parameters, it supports binding JSON data types too, implemented using Jackson API.
HelloFunction a template for JUnit tests had been generated too,
As you can see, it comes with a special
FnTestingRule JUnit rule which allows for calling the function.
shouldReturnGreeeting first enqueues an empty event (without a body) and then calls the
HelloFunction acting on behalf of the enqueued event.
To execute our function JUnit tests, you can run
fn build. The underlying Maven build should run the function tests is part of the build.
More to come
In this article we only saw the tip of the iceberg. For example, the Fn platform also comes with database and message queues support, allowing for persistent storage and messaging between (asynchronous) function calls.
There is another very interesting Fn feature: Flows. Flows allow you to orchestrate multiple function calls and implement asynchronous functions which will be consumed by a long-running server component (the completer) in the end. For an example of function orchestration, we will refer to the async thumbnail generation example on GitHub.
As last example, we will show how to use this so-called completer together with Fn Flows to get an impression on about this topic.
Start our function container on port 8080 again:
Start the completer container:
docker ps to see if our two containers are running:
Create new function
Remove the generated Java files and create a new function called
Now change the
func.yaml function configuration to:
and create a new Fn app and run the function:
Now we have to configure our Flow function to talk to the completer we started just before:
Once we have set the
COMPLETER_BASE configuration property, we have set up the Flow correctly. We can now run our function
Flows provide a meta-level on top of the functions and there are many more concepts and asynchronous programming patterns supported by Fn. If you are interested you can start with the Flow User Guide for more information.
The Fn Project has been announced and open-sourced by Oracle at JavaOne 2017 this year. Fn adds support for creating, testing, running and deploying functions in serverless architectures or in public or private clouds (so basically everywhere), utilising FaaS, functions-as-a-service. This article has a first look on Fn and how to use its Java support together with FDK to write serverless functions.