OpenFaaS Lab 3

Chaining functions

Posted by Krystian Wojcicki on Monday, July 29, 2019 Tags: Guide   5 minute read

Lab 3

  • Chaining functions on the user and OpenFaaS side

There will be situations where it will be useful to take the output of one function and use it as an input to another. This can be done both client-side and using the API Gateway.

Chaining functions on the client-side

You can pipe the result of one function into another using curl, the faas-cli or some of your own code. Here’s an example:

Pros:

  • requires no code - can be done with CLI programs
  • fast for development and testing
  • easy to model in code

Cons:

  • additional latency - each function goes back to the server
  • chatty (more messages)

Heres an example

kwojcicki@ubuntu:~/workspace/openfaas-workshops$ echo -n "" | faas-cli invoke nodeinfo --gateway $ip:31112 | faas-cli invoke markdown --gateway $ip:31112
<p>Hostname: nodeinfo-7dd947cd99-7c8zd</p>

<p>Platform: linux
Arch: x64
CPU count: 6
Uptime: 3378</p>

Chaining functions on the server-side

The easiest way to call one function from another is make a call over HTTP via the OpenFaaS API Gateway. This call does not need to know the external domain name or IP address, it can simply refer to the API Gateway as gateway through a DNS entry.

Pros:

  • functions can make use of each other directly
  • low latency since the functions can access each other on the same network

Cons:

  • requires a code library for making the HTTP request

We are going to be adding onto our wc function in order to filter out common words such as ‘a’, ‘the’, ‘of’. To do this we will generate 2 more functions, one which will filter out common words from a string filter and another to perform the chaining wc-filtered. Again these example functions are written in python3 but any language can be used.

Here we will generate one yaml file containing the definition of both the filter and wc-filtered function.

faas new --lang python3 filter
faas new --lang python3 wc-filtered --append filter.yml

Will write filter first, this function will take in a string and return a string without any ‘a’, ‘the’, ‘of’.

def handle(req):
    """handle a request to the function
    Args:
        req (str): request body
    """

    COMMON_WORDS = {'a', 'the', 'of'}

    words = req.split()
    words = [word for word in words if word.lower() not in COMMON_WORDS]
    return " ".join(words)


if __name__ == '__main__':
    print(handle("hello of the world"))

Great now we need to chain these two functions together, wc-filtered will do that for us.

import requests

def handle(req):
    """handle a request to the function
    Args:
        req (str): request body
    """

    r = requests.get("http://gateway.openfaas:8080/function/filter", data=req)

    if r.status_code != 200:
        sys.exit("Error with filter, expected: %d, got: %d\n" % (200, r.status_code))

    filter_req = r.text

    r = requests.get("http://gateway.openfaas:8080/function/wc", data=filter_req)

    if r.status_code != 200:
        sys.exit("Error with wc, expected: %d, got: %d\n" % (200, r.status_code))

    return r.json()

You may have noticed we are importing requests which is not actually part of Pythons standard library. To pull this library we need to add requests to ./wc-filtered/requirements.txt

Now lets deploy wc-filtered and filter to test them out

faas build -f filter.yml
kind load docker-image filter:latest
kind load docker-image wc-filtered:latest
faas deploy -f filter.yml --gateway $ip:31112

Now lets test it out

kwojcicki@ubuntu:~/workspace/openfaas-workshops$ echo "hello of the world" | faas invoke filter --gateway $ip:31112
hello world
kwojcicki@ubuntu:~/workspace/openfaas-workshops$ echo "hello of the world" | faas invoke wc-filtered --gateway $ip:31112
{'hello': 1, 'world': 1}

One of the problems of doing server-side chaining is the functions become very dependent on one another faas-flow tries to solve this.