Tuesday, November 28, 2023

Tips and tricks for using IBM Cloud Code Engine functions

Utilize Code Engine runtime information
Over the past weeks, I started to use IBM Cloud Code Engine functions. Code Engine is IBM Cloud's fully managed, serverless platform to run containerized workloads. It offers apps, jobs, and most recently functions (Function-as-a-Service, Faas) as deployment model. The following tips and tricks help you in cutting down deployment cycles and in designing function-based APIs.

Local testing of functions

Code Engine apps are regular web applications, jobs are like scripts, and both can be tested locally in several ways. Because functions are code snippets, some wrapper is needed to turn them into programs. The following approach has served me well so far. With the function code in a subdirectory “func”, I utilize either the Python or Node.js wrapper code shown below and place it in the parent directory. There, I also maintain files with test configurations as JSON objects, similar to what is passed by Code Engine to the function on invocation. For testing, I run the wrapper along with the configuration file as parameter. The wrappers for Python and Node.js are shown below, Python first:

# syntax: python wrapper.py params.json

# import the Code Engine function: func/__main__.py
from func.__main__ import main
import sys, json

if __name__ == "__main__":
    # open file, read JSON config
    with open(str(sys.argv[1])) as confFile:
        params=json.load(confFile)
    # invoke the CE function and print the result
    print(main(params))

A Node.js wrapper is similar:

// syntax: node wrapper.js params.json

// require the Code Engine function: func/main.js
var func=require('./func/main.js')

// read the file with function parameters
const fs = require("fs");
const data = fs.readFileSync(process.argv[2]);

// invoke the CE function and log the result
console.log(func.main(JSON.parse(data)));

Environment variables and API design

For designing your API and functions namespace, you can utilize Code Engine-injected environment variables like __ce_path and __ce_method. The former holds the path component of the requested URL like “/object”, the latter the HTTP method like GET or POST. By switching on the supplied values for these variables, you can serve multiple API functions from the same Code Engine function. The benefit is a single base URL. Depending on your project and code management, you might even want to combine this approach with separating each API function implementation into its own file - similar to the wrapper approach shown above.

Job-like functions

Sometimes, you might need the HTTP endpoint of a function and the possibly longer execution time of a jon. In that case, create both a function and a job. Then, utilize the Code Engine API to create a job run from within the function. In this hybrid approach the function can get called via its HTTP endpoint and terminates after kicking off the job run. A job could then run up to 24 hours and benefit from the parallel job processing capabilities in Code Engine. You can find a sample implementation of this pattern in the Code Engine code examples.

Conclusions

The above tricks helped me to efficiently use Code Engine functions and to utilize them for my projects. Especially, knowing how to test functions locally before deploying them to a cloud environment, cuts down the development cycle.

If you have feedback, suggestions, or questions about this post, please reach out to me on Twitter (@data_henrik), Mastodon (@data_henrik@mastodon.social), or LinkedIn.