Large (Java) Applications on Apache OpenWhisk

This blog post will explain how to run large Java applications on Apache OpenWhisk.

Java actions are deployed from JAR files containing application class files. External libraries can be used by bundling those dependencies into a fat JAR file. The JAR file must be less than the maximum action size of 48MB.

So, what if the application uses lots of external libraries and the JAR file is larger than 48MB? 🤔

Apache OpenWhisk’s support for custom Docker runtimes provides a workaround. In a previous blog post, we showed how this feature could be used with Python applications which rely on lots of external libraries.

Using the same approach with Java, a custom Java runtime can be created with additional libraries pre-installed. Those libraries do not need to be included in the application jar, which will just contain private class files. This should hopefully reduce the JAR file to under the action size limit.

Let’s walk through an example to show how this works….

Example Java Class using External Libraries

import com.google.gson.JsonObject;
import org.apache.commons.text.WordUtils;

public class Capitialize {
    public static JsonObject main(JsonObject args) {
        String name = args.getAsJsonPrimitive("message").getAsString();
        JsonObject response = new JsonObject();
        response.addProperty("capitalized", WordUtils.capitalize(name));
        return response;
    }
}

This example Java action capitalises sentences from the input event. It uses the Apache Commons Text library to handle [capitialisation](https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/WordUtils.html#capitalize(java.lang.String)) of input strings. This external library will be installed in the runtime, rather than bundled in the application JAR file.

Build Custom Java Runtime

git clone https://github.com/apache/incubator-openwhisk-runtime-java
  • Edit the core/java8/proxy/build.gradle file and update the dependencies configuration with extra dependencies needed in the runtime.
dependencies {
    compile 'com.google.code.gson:gson:2.6.2'
    compile 'org.apache.commons:commons-text:1.6' // <-- the additional library
}

Note: com.google.code.gson:gson:2.6.2 is used by the runtime to handle JSON encoding/decoding. Do not remove this dependency.

  • Execute the following command to build the custom Docker image.
./gradlew core:java8:distDocker

Push Image To Docker Hub

If the build process succeeds, a local Docker image named java8action should be available. This needs to be pushed to Docker Hub to allow Apache OpenWhisk to use it.

docker tag java8action <DOCKERHUB_USERNAME>/java8action
  • Push the tagged custom image to Docker Hub.
docker push <DOCKERHUB_USERNAME>/java8action

Create OpenWhisk Action With Custom Runtime

  • Compile the Java source file.
javac Capitialize.java
  • Create the application JAR from the class file.
jar cvf capitialize.jar Capitialize.class
  • Create the Java action with the custom runtime.
wsk action create capitialize capitialize.jar --main Capitialize --docker <DOCKERHUB_USERNAME>/java8action

--main is the class file name containing the action handler in the JAR file. --docker is the Docker image name for the custom runtime.

Test it out!

  • Execute the capitialize action with input text to returned capitalised sentences.
wsk action invoke capitialize -b -r -p message "this is a sentence"

If this works, the following JSON should be printed to the console.

{
    "capitalized": "This Is A Sentence"
}

The external library has been used in the application without including it in the application JAR file! 💯💯💯

Conclusion

Apache OpenWhisk supports running Java applications using fat JARs, which bundle application source code and external dependencies. JAR files cannot be more than 48MB, which can be challenging when applications uses lots of external libraries.

If application source files and external libraries result in JAR files larger than this limit, Apache OpenWhisk’s support for custom Docker runtimes provide a solution for running large Java applications on the platform.

By building a custom Java runtime, extra libraries can be pre-installed in the runtime. These dependencies do not need to be included in the application JAR file, which reduces the file size to under the action size limit. 👍