npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@projectriff/node-function-invoker

v0.3.0

Published

riff invoker for Node functions

Downloads

8

Readme

Node Function Invoker

CI

Purpose

The node function invoker provides a host for functions consisting of a single NodeJS module. It adheres to riff streaming protocol and invokes functions accordingly.

Supported functions

Non-streaming functions (a.k.a. request-reply functions)

Non-streaming functions, more specifically "request-reply" functions, such as:

module.exports = (x) => x ** 2;

will be automatically promoted to streaming functions via the equivalent of the map operator.

Request-reply functions can also be asynchronous:

module.exports = async (x) => x ** 2;

or return a Promise:

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

Finally, note that the interaction model can be explicitly advertised, albeit this is not necessary:

module.exports = (x) => x ** 2;
module.exports.$interactionModel = 'request-reply';

Streaming functions

Streaming functions must comply to the following signature:

module.exports = (inputStreams, outputStreams) => {
    const { numbers, letters } = inputStreams;
    const { repetitions } = outputStreams;
    // do something
};
module.exports.$interactionModel = 'node-streams';

Please note that streaming functions must always declare the corresponding interaction mode.

Streams can also be looked up by index:

module.exports = (inputStreams, outputStreams) => {
    const firstInputStream = inputStreams.$order[0];
    const firstOutputStream = outputStreams.$order[0];
    const secondOutputStream = outputStreams.$order[1];
    // do something
};
module.exports.$interactionModel = 'node-streams';

Input streams are Readable streams.

Output streams are Writable streams.

The function must end the output streams when it is done emitting data or when an error occurs (if the output streams are pipe'd from input streams, then this is automatically managed).

Message support

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.

By default, request-reply functions accept and produce payloads. They can be configured instead to receive either the entire message or the headers only.

Streaming functions can only receive messages. Configuring them with $argumentType will trigger an error. However, they can produce either messages or payloads, just like request-reply functions.

Receiving messages
// a request-reply 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 messages
module.exports.$argumentType = 'message';
Producing messages

To produce messages, functions should install the @projectriff/message package:

npm install --save @projectriff/message
const { Message } = require('@projectriff/message');

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

// a request-reply 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();
};

Lifecycle

Functions that communicate with external services, like a database, can use the $init and $destroy lifecycle hooks on the function. These methods are called once per process.

The $init method is guaranteed to finish before the main function is invoked for the first time.

The $destroy method is guaranteed to be invoked after all of the main functions are finished, before the process shuts down.

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. Note that the lifecycle hooks must be fields on the exported function. The hooks may be either synchronous or async functions. Lifecycle functions have up to 10 seconds to complete their work, or the function invoker will abort.

Supported protocols

This invoker supports only streaming, and complies to riff streaming protocol. However, it is possible to send HTTP requests and receive HTTP responses if you combine this invoker with the streaming HTTP adapter available here.

Development

Prereqs

  • Node version required: 10 (LTS), 12 (LTS) or 13.
  • Make sure to install the EditorConfig plugin in your editing environment.

Build

  • Install dependencies by running npm ci.
  • Run the tests with npm test

Run

Streaming

Execute the following:

 $ cd /path/to/node-function-invoker
 $ FUNCTION_URI="/absolute/path/to/function.js" NODE_DEBUG='riff' node server.js

Request-reply only

If you just want to test request-reply functions, clone the Streaming HTTP adapter and run:

 $ cd /path/to/streaming-http-adapter
 $ make
 $ FUNCTION_URI="/absolute/path/to/function.js" NODE_DEBUG='riff' ./streaming-http-adapter node /path/to/node-function-invoker/server.js

You can then send HTTP POST requests to http://localhost:8080 and interact with the function.

Source formatting

We use prettier style checks to enforce code consistency. Many editors can automatically reformat source to match this style. To manually request formatted source run npm run format.