riff is for functions

riff is for functions

  • Docs
  • Blog
  • GitHub
  • Slack

›Function Invokers

Version (v0.6 snapshot)

  • v0.5.x
  • v0.4.x
  • v0.3.x

Getting Started

  • Pick your environment
  • GKE
  • Minikube
  • Docker for Mac
  • Docker for Windows
  • kind

Runtimes

  • Core
  • Knative
  • Streaming

Function Invokers

  • Java
  • Node.js
  • Command

CLI Reference

  • riff
  • riff doctor
  • riff completion
  • Credential

    • riff credential
    • riff credential apply
    • riff credential delete
    • riff credential list

    Build

    • riff function
    • riff function create
    • riff function delete
    • riff function list
    • riff function status
    • riff function tail
    • riff application
    • riff application create
    • riff application delete
    • riff application list
    • riff application status
    • riff application tail
    • riff container
    • riff container create
    • riff container delete
    • riff container list
    • riff container status

    Knative Runtime

    • riff knative
    • riff knative adapter
    • riff knative adapter create
    • riff knative adapter delete
    • riff knative adapter list
    • riff knative adapter status
    • riff knative deployer
    • riff knative deployer create
    • riff knative deployer delete
    • riff knative deployer list
    • riff knative deployer status
    • riff knative deployer tail

    Core Runtime

    • riff core
    • riff core deployer
    • riff core deployer create
    • riff core deployer delete
    • riff core deployer list
    • riff core deployer status
    • riff core deployer tail

    Streaming Runtime

    • riff streaming
    • riff streaming stream
    • riff streaming stream create
    • riff streaming stream delete
    • riff streaming stream list
    • riff streaming stream status
    • riff streaming processor
    • riff streaming processor create
    • riff streaming processor delete
    • riff streaming processor list
    • riff streaming processor status
    • riff streaming processor tail
    • riff streaming gateway
    • riff streaming gateway list
    • riff streaming gateway status

    In-memory Gateway

    • inmemory-gateway
    • inmemory-gateway create
    • inmemory-gateway delete
    • inmemory-gateway list
    • inmemory-gateway status

    Kafka Gateway

    • kafka-gateway
    • kafka-gateway create
    • kafka-gateway delete
    • kafka-gateway list
    • kafka-gateway status

    Pulsar Gateway

    • pulsar-gateway
    • pulsar-gateway create
    • pulsar-gateway delete
    • pulsar-gateway list
    • pulsar-gateway status
Edit

Node Function Invoker

JavaScript functions are invoked using a Node Function Invoker that is provided by riff when building the function.

The Node Function Invoker provides a host for functions consisting of a single Node.js module. It accepts HTTP requests, invokes the function for each request, and sends the function's output to the HTTP response.

Authoring a function

At runtime, the node function invoker uses require() to load the target function module. This module must export the function to invoke.

// square
module.exports = x => x ** 2;

The first argument is the triggering message's payload and the returned value is the resulting message's payload.

async

Asynchronous work can be completed by defining either an async function or by returning a Promise.

// async
module.exports = async x => x ** 2;

// promise
module.exports = x => Promise.resolve(x ** 2);

streams (experimental)

Streaming functions can be created by setting the $interactionModel property on the function to node-streams. They must set the $arity to tell the invoker how many (input and output) streams they require.

NOTE: the $arity setting is temporary and will go away in a future release.

The function is invoked with two arguments:

  • inputs, a dictionary of Readable Streams
  • outputs, a dictionary of Writeable Streams

All of these streams are object streams and are currently only indexed by declaration order ("0", "1"...).

NOTE: the streams may also be indexed by name in a future release.

Any value returned by the function is ignored, new messages must be written to the output stream.

// echo.js
module.exports = (inputs, outputs) => {
  inputs["0"].pipe(outputs["0"]);
};
module.exports.$interactionModel = "node-streams";
module.exports.$arity = 2;

Any npm package that works with Node Streams can be used.

// upperCase.js
const miss = require("mississippi");

const upperCaser = miss.through.obj((chunk, enc, cb) => {
  cb(null, chunk.toUpperCase());
});

module.exports = (inputs, outputs) => {
  inputs["0"].pipe(upperCaser).pipe(outputs["0"]);
};
module.exports.$interactionModel = "node-streams";
module.exports.$arity = 2;

messages vs payloads

By default, functions accept and produce payloads. Functions that need to interact with headers can instead opt to receive and/or produce messages. A message is an object that contains both headers and a payload. Message headers are a map with case-insensitive keys and multiple string values.

Since JavaScript and Node have no built-in type for messages or headers, riff uses the @projectriff/message npm module. To use messages, functions should install the @projectriff/message package:

npm install --save @projectriff/message

receiving messages

const { Message } = require('@projectriff/message');

// a function that accepts a message, which is an instance of Message
module.exports = message => {
    const authorization = message.headers.getValue('Authorization');
    ...
};

// tell the invoker the function wants to receive whole messages
module.exports.$argumentTransformers = [(message) => { return message; }];

producing messages

const { Message } = require("@projectriff/message");

const instanceId = Math.round(Math.random() * 10000);
let invocationCount = 0;

// a function that produces a Message
module.exports = name => {
  return Message.builder()
    .addHeader("X-Riff-Instance", instanceId)
    .addHeader("X-Riff-Count", invocationCount++)
    .payload(`Hello ${name}!`)
    .build();
};

// the following is the same as the default applied argument transformer
module.exports.$argumentTransformers = [(message) => { return message.payload; }];

cardinality

In the case of request-reply functions (like the above ones), there must be at most one argument transformer.

In the case of streaming functions, there must be either 0 or as many declared argument transformers as there are input streams.

lifecycle

Functions that communicate with external services, like a database, can use the $init and $destroy lifecycle hooks on the function. These methods are invoked once per function invoker instance, whereas the target function may be invoked multiple times within a single function invoker instance.

The $init method is guaranteed to finish before the main function is invoked. The $destroy method is guaranteed to be invoked after all of the main functions are finished.

let client;

// function
module.exports = async ({ key, amount }) => {
  return await client.incrby(key, amount);
};

// setup
module.exports.$init = async () => {
  const Redis = require("redis-promise");
  client = new Redis();
  await client.connect();
};

// cleanup
module.exports.$destroy = async () => {
  await client.quit();
};

The lifecycle methods are optional, and should only be implemented when needed. The hooks may be either traditional or async functions. Lifecycle functions have up to 10 seconds to complete their work, or the function invoker aborts.

Creating a function

The node runtime is detected when either there is a package.json file in the root, or the artifact is specified as a .js file.

bare modules

To deploy a bare Node.js module, the artifact must be specified.

riff function create square  --artifact square.js \
  --git-repo https://github.com/projectriff-samples/node-square

packages

Functions may define a package.json to specify dependent packages to install as well as the main module.

// hello.js
module.exports = name => `Hello ${name}!`
// package.json
{
  ...
  "main": "hello.js",
  ...
}
riff function create hello \
  --git-repo https://github.com/projectriff-samples/node-hello

Deploying the function

Please see the runtime documentation for how to deploy and invoke the function.

  • Core runtime -- for request-reply functions only!
  • Knative runtime -- for request-reply functions only!
  • Streaming runtime

Cleanup

When done with the function, delete the function resource to stop creating new builds.

NOTE: Images built by the function continue to exist in the container registry and may continue to be consumed by a runtime.

riff function delete square
Deleted function "square"
← JavaCommand →
  • Authoring a function
    • async
    • streams (experimental)
    • messages vs payloads
    • lifecycle
  • Creating a function
    • bare modules
    • packages
  • Deploying the function
  • Cleanup
riff is for functions
Docs
Versions
Community
BlogGitHubSlackKnativeTwitter
More
Privacy PolicyTerms of UseCode of Conduct
Deployed by Netlify
Copyright © 2021 VMware, Inc