Workflow orchestration for your Go functions using Fn Flow
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
blobstore
client
examples
models
vendor
.gitignore
Gopkg.lock
Gopkg.toml
LICENSE
Makefile
README.md
client.go
codecs.go
conversions.go
flows.go
invocations.go

README.md

Serverless Workflows with Go

Easily create serverless workflows directly in Go with the power of Fn Flow.

Quick Intro

Simply import this library into your go function, build and deploy onto Fn. Flows use the fdk-go to handle interacting with Fn, below is an example flow:

package main

import (
	"fmt"
	"strings"
	"time"

  	fdk "github.com/fnproject/fdk-go"
  	flows "github.com/fnproject/flow-lib-go"
)

func init() {
  	flows.RegisterAction(strings.ToUpper)
  	flows.RegisterAction(strings.ToLower)
}

func main() {
	fdk.Handle(flows.WithFlow(
    		fdk.HandlerFunc(func(ctx context.Context, r io.Reader, w io.Writer) {
      			cf := flows.CurrentFlow().CompletedValue("foo")
      			valueCh, errorCh := cf.ThenApply(strings.ToUpper).ThenApply(strings.ToLower).Get()
      			select {
      			case value := <-valueCh:
        			fmt.Fprintf(w, "Flow succeeded with value %v", value)
      			case err := <-errorCh:
        			fmt.Fprintf(w, "Flow failed with error %v", err)
      			case <-time.After(time.Minute * 1):
        			fmt.Fprintf(w, "Timed out!")
      			}
    		}),
  	)
}

Where do I go from here?

A variety of example use-cases is provided here.

FAQs

How are values serialized?

Go's gob serialization mechanism is used to encode/decode values for communication with the completer.

What kinds of values can be serialized?

Booleans, string, structs, arrays and slices are supported. Functions, closures and channels are not.

How are continuations serialized?

Since Go does not support serializing closures/functions due to its statically compiled nature, they are in fact not serialized at all. Go functions implementing a continuation need to be explicitly registered by calling flows.RegisterAction(actionFunction) typically inside the handler's init function. Registering actions assigns a unique and stable key that can be serialized and used to look up a pointer to the function during a continuation invocation.

Why do actions need to be registered?

See above.

Can I use closures or method receivers in my continuations?

No. Only continuation actions implemented with functions are supported, since they are stateless. No state will be serialized with a continuation. Although possible, invoking a method receiver is not currently supported inside continuations.

How does error-handling work?

Go allows functions to return error types in addition to a result via its support for multiple return values. If a continuation function returns a (non-nil) error as its second return value, its error message will be serialized and form the failed value of that stage.

If a panic occurs while invoking the continuation function, the panic value will be captured and the stage failed with the same value.

Can I invoke other fn functions?

Yes. flows.CurrentFlow().InvokeFunction("your_function_id", req), where the function ID is a value like 01CQV4NEGMNG8G00GZJ0000002 and can be resolved with the following command:

fn inspect function your_app your_function | grep fnproject.io/fn/invokeEndpoint

See here for a full example.