/ Fn Project

Groovy functions with Oracle Fn Project

The Fn Project is a new Open Source FAAS (Function-As-A-Service) framework by Oracle. In contrast to what Amazon or Google provides this framework is fully open source and can be set up on your local hardware or on any VPC provider. In this short introduction I'll show you how you can easily start building your functions with Groovy and Gradle.

The FN Project framework consists of many parts to be able to load balance and scale the framework infrastructure so it might seem daunting. But don't worry, you won't need any of that for this tutorial! We are only going to look into how we can develop a function and deploy it to a single server, the operations part can come later. There are a few things you need to install first though.

To be able to run the Fn Server you will need a Docker enabled host. So if you don't yet have Docker installed install it first.

You also will need to have Gradle installed.

You have Docker and Gradle installed now? Good!

Before we begin, the question we got to ask ourselves first is, what is a Fn function anyway?

A Fn function is in essence a small program that has some inputs (the HTTP Request) and from those inputs will produce some output (the HTTP Response). It does not really matter in which programming language the function is written as long as the inputs and outputs are defined. In fact the Oracle Fn Project is programming language agnostic and allows you to use any language you prefer if you want.

But if our functions can be written in any language, how can it all be deployed on the same server?

This is where Docker comes in. Every function is wrapped in a Docker image provided by the Fn Project that handles routing the HTTP request information from the FN Server to the function running in the Docker container and routing the response from your function back to the caller. This is what the Fn Project maintainers calls cloud native. While all this routing might sound tricky (and most likely is internally), for the function developer it is made fully transparent.

If you already took a look at the Fn Project documentation you most likely noticed that currently they offer the following language choices of writing functions:

  • Go
  • Java
  • Node.js
  • Ruby
  • Python

They also offer a CLI for simplifying creating functions in those languages.

However, while all of those are good languages and the CLI is ok to use I felt that I wanted a bit more mature tool stack to work with, so I set out to write support for using Gradle to both build and deploy the function and allow developers also to leverage Groovy for writing functions.

Introducing a new Gradle plugin for building Groovy Fn functions

So lets have a look at how we can write our functions with Groovy and deploy it with Gradle!

Start by creating a new folder (in this example I used hello-fn as the folder name) somewhere on your system.

In that folder add an empty build.gradle file.

The new plugin is located the Gradle Plugin Portal so you can easily include it in your project by adding the following to your build.gradle:

plugins {
    id 'groovy'
    id 'com.devsoap.fn' version '0.0.7'
}

After you have applied the plugin the following tasks will be made available for your gradle project (you can check by running gradle tasks):

Fn tasks
--------
fnCreateFunction - Creates a Fn Function project
fnDeploy - Deploys the function to the server
fnDocker - Generates the docker file
fnInstall - Installs the FN CLI
fnInvoke - Invokes the function on the server
fnStart - Starts the local FN Server
fnStop - Stops the local FN Server

Before we run any of the tasks, we still need to add a bit of configuration to our build.gradle so the Gradle plugin knows how to create a correct function.

fnDocker {
    functionClass = 'com.example.HelloWorld'
    functionMethod = 'sayHello'
}

We will also need some more dependencies so add those as well:

repositories {
    mavenCentral()
    maven { url 'https://dl.bintray.com/fnproject/fnproject' }
}

dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.5.3'
    compile "com.fnproject.fn:api:1.0.74"
}

Right, now we are ready to run the fnCreateFunction task to create our function structure.

Once you have run the task it should have created the following folder structure:

hello-fn
├── build.gradle
└── src
    └── main
        └── groovy
            └── com
                └── example
                    └── HelloWorld.groovy
                    

Not much boiler plate code there.

Lets have a look at the generated HelloWorld.groovy class:

package com.example

class HelloWorld {

    String sayHello(String input) {
        String name = input ?: 'world'
        "Hello, $name!"
    }
}

It couldn't be much simpler than this, it is a simple class with one method, sayHello, that takes a string input and assumes it is a name and returns a greeting for that name.

Of course in real-world situations you will most likely want to do a lot more like reading request headers, setting response headers and generating different content-type payloads. This is all achievable using the Java FDK the FN Project provides.

Deploying the function locally

Now that we have our function, we most likely want to test it out locally before we put it in production.

To start the development server locally the Gradle plugin provides you with an easy task to use, fnStart. When you run that task it will download the CLI and start the FN Server on your local Docker instance.

$ docker ps
CONTAINER ID        IMAGE                COMMAND             CREATED             STATUS              PORTS                              NAMES
30c96567802a        fnproject/fnserver   "./fnserver"        5 seconds ago       Up 4 seconds        2375/tcp, 0.0.0.0:8080->8080/tcp   fnserver

Once it successfully has started it should be running on port 8080. If you want to stop the server you can run fnStop which will terminate the server.

Once the server is running we can deploy our function there. This can be achieved by running fnDeploy.

It will first build a docker image and then deploy the image to the FN Server.

$ gradle fnDeploy
> Task :fnDeploy

Building image hello-fn:latest 

BUILD SUCCESSFUL in 23s
6 actionable tasks: 6 executed

If everything went fine the function should now be deployed and ready to use.

Testing our function locally

The plugin comes with a built in way of testing our running function.

By using the task fnInvoke we can issue a request to the function.

$ gradle fnInvoke

> Task :fnInvoke
Hello, world!

And if we post some input to the function:

$ gradle fnInvoke --method=POST --input=John

> Task :fnInvoke
Hello, John!

Of course the fnInvoke function is limited in what it can do and for more advanced use-cases we might want to use a separate app for testing queries (my favourite being Insomnia :) ).

To do that point your REST client to http://localhost:8080/t/<app name>/<trigger name> where in the example case the app name and trigger name is the same so the url would be http://localhost:8080/hello-fn/hello-fn. This is also what fnInvoke calls in the background.

Development tip: While developing the function locally you can make Gradle continuously monitor the source files and when you change something then it will automatically re-deploy the function. You can do that by running the fnDeploy task with the -t parameter like so gradle -t fnDeploy.

Taking the function to production

Once you have the function working locally you can deploy it to production quite easily by adding a few parameters to build.gradle.

fnDeploy {
  registry = '<docker registry url>'
  api = '<FN Server URL>'
}

Now if you run the fnDeploy task the function will be deployed to your remote Docker registry and FN Server.

And beyond...

This was just a short introduction into how you can work with Gradle and Groovy to make your functions. There are plenty of other fun things you can do with these functions, for example if you want to see a bit more advanced demo you can have a look at the CORS proxy example here https://github.com/devsoap/examples/tree/master/fn-cors-proxy.

For more information about how to use the plugin see https://github.com/devsoap/fn-gradle-plugin

If you find any issues do not hesitate to create an issue at https://github.com/devsoap/fn-gradle-plugin/issues

Thanks for reading, I hope to get your feedback on this project!