Serverless Functions for Business Logic

This section discusses how to implement business behavior using serverless functions.

What is a Trillo Serverless Function?

Trillo serverless function implements some business logic and it can be invoked using restful API.

A serverless function is automatically published as an API.

Create a Function

Creating a serverless function using Trillo Workbench is simple. Simply select the Functions menu options in the left navigation. Select + New Function.

Currently, Trillo Workbench supports only Java and Python languages.

Say, you create a function by giving it a name as MyFunction. The function will be created with the following stubbed code.

import java.util.Map;
import com.collager.trillo.util.Api;
import com.collager.trillo.util.ServerlessFunction;

public class MyFunction extends ServerlessFunction {

  @Api(httpMethod="post")
  public Object postMethodChangeMe(Map<String, Object> parameters) {
    return parameters;
  }
}

In the above code, MyFunction is the name of the function. It has a method 'postMethodChangeMe'. This serves as an API endpoint. It is of type HTTP post due to the annotation above the method. Note that the function implements the ServerlessFunction class (which implements TrilloFunction). More about it below.

THe URL that will target this function and its method would be as follows:

<hostname>/ds/function/shared/MyFunction/postMethodChangeMe

where,

  1. ds/function indicates the service of Trillo Workbench (data dervice and its function module).

  2. shared is package (folder) containing the function.

  3. MyFunction is the name of the function that is the target of URL.

  4. postMethodChangeMe is the method that will be invoked due to API call.

A function can support more than one endpoint (callable methods as API). The names of the methods can be anything (generally reflect the purpose). Say the above MyFunction needs to support the following 4 methods:

  1. saveValue

  2. updateValue

  3. getValue

  4. removeOverheads

The refined MyFunction will be as follows.

import java.util.Map;
import com.collager.trillo.util.Api;
import com.collager.trillo.util.ServerlessFunction;

public class MyFunction extends ServerlessFunction {

  @Api(httpMethod="post")
  public Object saveValue(Map<String, Object> parameters) {
    return parameters;
  }
  
  @Api(httpMethod="put")
  public Object updateValue(Map<String, Object> parameters) {
    return parameters;
  }
  
  @Api(httpMethod="get")
  public Object getValue(Map<String, Object> parameters) {
    return parameters;
  }
  
  @Api(httpMethod="delete")
  public Object removeOverheads(Map<String, Object> parameters) {
    return parameters;
  }

}

In this case, the function will publish 4 endpoints.

  1. a post endpoint as /ds/function/shared/MyFunction/saveValue.

  2. a put endpoint as /ds/function/shared/MyFunction/updateValue.

  3. a get endpoint as /ds/function/shared/MyFunction/getValue.

  4. a delete endpoint as /ds/function/shared/MyFunction/removeOverheads.

ServerlessFunction (BaseClass of Trillo Function)

ServerlessFunction is the base class of Trillo functions class. This encapsulates runtime context provides access to its properties such as user identity, task id, stateMap. All These properties are available to any subclass using accessor methods.

All Trillo serverless function runs within a transaction boundary. By default, the transaction is rolled back if the function invocation returns a Result object with an error. Since a function may run a few steps that may be committed irrespective of the final result, Trillo SDK provides an API to commit the transaction. After a transaction is committed, a new transaction is created.

Sample Hello World Function

The sample code with a method called "sayHello" as the endpoint:

@Api(httpMethod="get")
private Object sayHello(Map<String, Object> parameters) {
    String hello = "Hello from, " + getUserId();
    if (parameters.containsKey("youSaid")) {
      hello += "\n You said, " + parameters.get("youSaid");
    }
    return hello;
}

Notice that this method simply echos "Hello from <current user id>". The current user id is accessed from the runtime context. The function adds the parameter "youSaid" if it is passed.

Test Function

The sample code with a method called "sayHello" as the endpoint:

Result

Notice in the above figure, that the actual result is wrapped inside an object and passed as its data attribute. The wrapper class is Result (a Java class/ python class). It contains the actual result in the data attribute. It has other attributes for status, error message, detailed message, etc. A special attribute called _rtag is included with a special value _r_ to assist a JavaScript client in identifying if the returned value is an instance of Result.

Log Messages In a Function

The serverless function can use logging APIs available in Trillo SDK. See the modified example code below:

private Object _handle(ScriptParameter params) {
    //Insert the correct biz logic
    LogApi.info("Entered _handle()");
    Map<String, Object> functionParameters = (Map<String, Object>)params.getV();
    String hello = "Hello, " + params.getUserId();
    if (functionParameters.containsKey("youSaid")) {
      hello += "\n you said, " + functionParameters.get("youSaid");
    }
    LogApi.loginfo("Exiting _handle()");
    return hello;
}

Audit Logs

Audit logs are similar to the log messages discussed above with the distinction that these calls also log messages in the database. This is useful for auditing important business events. It is also useful to track, troubleshoot, and monitor the status of long-running jobs.

The following code shows how to use logging vs audit logs.

Tapix.auditInfo("actionName", "Entered _handle()");    // this is a log
Tapix.auditInfo("actionName", "Entered _handle()"); // this is audit log

"actionName" can be any text. It is generally the action that caused this log, such as "BucketFileWrite". It is used to filter logs.

Samples

Trillo SDK (APIs) in a Function

Trillo SDK provides several APIs to simplify writing a serverless function code. These APIs include:

  • Database access

  • Google cloud service

  • External restful service

  • CVS, JSON file processing

  • ...

  • ...

  • many more

Not only Trillo SDK functions but several open-source libraries that are integrated with the Trillo runtime, become available for use in your serverless functions (such as Apache Commons for example).

Version 1 Serverless Function

Trillo function Version 1 (V1) supported only one endpoint per function, landing into a default method called "handle". They were always invoked using HTTP-Post irrespective of API semantics. An example of V1 is shown below.

import com.collager.trillo.pojo.Result;
import com.collager.trillo.pojo.ScriptParameter;
import com.collager.trillo.util.LogApi;
import com.collager.trillo.util.TrilloFunction;
import java.util.Map;

public class MyFunction implements TrilloFunction {

  public Object handle(ScriptParameter scriptParameter) {
    try {
      // actual implementation inside _handle()
      return _handle(scriptParameter);
    } catch (Exception e) {
      LogApi.error("Failed", e);
      return Result.getFailedResult(e.getMessage());
    }
  }

  @SuppressWarnings("unchecked")
  private Object _handle(ScriptParameter scriptParameter) {
    Map<String, Object> parameters = (Map<String, Object>)scriptParameter.getV();
    return parameters;
  }

}

Methods of Version 1 Function

A V1 serverless functions generally have the following two methods. The first, method called 'handle', is the default method and always required. The second method is optional. It could have been renamed or merged into first one.

  • handle: This is the entry point of the function that is invoked by the runtime by passing ScriptParameter (see below).

  • _handle: A private method that is invoked by the method handle.

  1. The 'handle' method catches all exceptions, unwraps all error messages, and passes as a Result object.

  2. You should implement your code in the _handle (you can rename it). T

  3. he endpoint of published by the function is /ds/function/MyFunction.

ScriptParameter

ScriptParamter provides equivalent functionality as provided by the superclass (ServerlessFunction) of Version 2 Trillo functions. It provides the same accessor methods as provided by the ServerlessFunction. In addition to it, it provides a method "getV" to retrieve the parameter passed to the function.

Last updated