workflow

package
v1.6.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 10, 2024 License: GPL-3.0 Imports: 6 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrWorkflowMissing               = errors.New("cannot run without Workflow")
	ErrStartNodeMissing              = errors.New("cannot run without the start node")
	ErrConditionDataMissing          = errors.New("condition data missing")
	ErrConditionCaseConnection       = errors.New("condition cases are not leading in any case to a node")
	ErrConditionConnectionsMissing   = errors.New("condition connections missing")
	ErrNotExist                      = errors.New("does not exist")
	ErrConfigGetWorkflowMissing      = errors.New("GetWorkflow missing in your config")
	ErrNodeImplementationNotProvided = errors.New("node impl not provided")
)

Functions

This section is empty.

Types

type Case

type Case struct {
	Name   string                 `json:"name"`
	Value  interface{}            `json:"value"`
	Detail string                 `json:"detail,omitempty"`
	Data   map[string]interface{} `json:"data,omitempty"`
}

type Config

type Config struct {
	//GetWorkflow is your function that provides workflows for embedded use.
	GetWorkflow func(id string) (*Workflow, error)
	//State is provided by the workflow engine. If you pass it for a new instance you should get the same state as before.
	State []Step
	//GetData is used in the execution of the condition and it provides the data in the Execute function of the NodeIF.
	GetData func() interface{}
	//NodeImpl contains your implementations of the node types. The key of the map is the node type.
	NodeImpl map[string]*NodeDef
}

* In this package there are a few words about internal, background and foreground nodes. The meaning of them is here explained. background node:

A background node is not blocking the process.
When you call Next, you get a background node with Current if it is a node at the end of the workflow otherwise you will get a foreground node if no error occurred.
In the background nodes implementation there should be always returned < proceed > true if no error occurred otherwise it is configured wrong.
Which means Execute is called once if no error occurred.
Background nodes can be skipped in the Previous call to be able to get back to the last foreground node if no error occurs.
Please note, there is no detection for wrong configuration of background nodes during runtime.
If your node implementation changes and has an effect on the execution type, you must keep the background flag consistent.

foreground node:

A foreground node is blocking the process.
When you call Next usually you should get the foreground node by calling Current. Foreground nodes have states in the node implementation that causes Execute to be called more than once.
For example a form node. It has at least two states. State one is presenting the form, state two or higher is validating the form.

internal node:

Currently there are just two internal nodes, which is workflow and condition.
These nodes are handled by the engine itself, they are visible in the Stack but they can also be visible in Current.
For example if the root workflow starts with another workflow or a condition.

type Connection

type Connection struct {
	NodeID    string      `json:"id"`
	CaseValue interface{} `json:"value,omitempty"`
}

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

* In this package there are a few words about internal, background and foreground nodes. The meaning of them is here explained. background node:

A background node is not blocking the process.
When you call Next, you get a background node with Current if it is a node at the end of the workflow otherwise you will get a foreground node if no error occurred.
In the background nodes implementation there should be always returned < proceed > true if no error occurred otherwise it is configured wrong.
Which means Execute is called once if no error occurred.
Background nodes can be skipped in the Previous call to be able to get back to the last foreground node if no error occurs.
Please note, there is no detection for wrong configuration of background nodes during runtime.
If your node implementation changes and has an effect on the execution type, you must keep the background flag consistent.

foreground node:

A foreground node is blocking the process.
When you call Next usually you should get the foreground node by calling Current. Foreground nodes have states in the node implementation that causes Execute to be called more than once.
For example a form node. It has at least two states. State one is presenting the form, state two or higher is validating the form.

internal node:

Currently there are just two internal nodes, which is workflow and condition.
These nodes are handled by the engine itself, they are visible in the Stack but they can also be visible in Current.
For example if the root workflow starts with another workflow or a condition.

func New

func New(wf *Workflow, conf Config) (*Engine, error)

func (*Engine) Close

func (me *Engine) Close() error

func (*Engine) Current

func (me *Engine) Current() (*Node, error)

Current is providing the target node and the recent error. The target node can be an internal node or background node as well. It depends on the structure of the workflow. This call is thread safe.

func (*Engine) HasNext

func (me *Engine) HasNext() bool

HasNext is providing the last state of being able to move forward. HasNext result is not guaranteed as the path can change during the execution with the provided data. This call is thread safe.

func (*Engine) HasPrevious

func (me *Engine) HasPrevious() bool

HasPrevious is providing the last state of being able to move one step back. The result is guaranteed. This call is thread safe.

func (*Engine) LoopNext

func (me *Engine) LoopNext() bool

LoopNext is the same as Next but it combines hasNext and err into one bool so it can be used easier in a loop. To ensure if everything went well, you can just call Current() which provides the recent error This call is thread safe.

func (*Engine) LoopPrevious

func (me *Engine) LoopPrevious(skipBackgroundNodes bool) bool

LoopPrevious is the same as Previous but it combines hasPrev and err into one bool, so it can be used easier in a loop. To ensure if everything went well, you can just call Current() which provides the recent error This call is thread safe.

func (*Engine) Next

func (me *Engine) Next() (bool, error)

Next is moving one node further in the workflow The recent error can be retrieved by Current() as well. This call is thread safe.

func (*Engine) Previous

func (me *Engine) Previous(skipBackgroundNodes bool) (bool, error)

Previous is moving one or more steps back. A step consists of background nodes and foreground nodes. By skipping background nodes it moves back to a foreground node if there is one otherwise it stops at the beginning. This call is thread safe.

func (*Engine) Stack

func (me *Engine) Stack() []Stack

Stack is providing a slice containing all the executed nodes no matter if it was during forward or backward. It contains internal nodes like workflow or condition. This call is thread safe.

func (*Engine) State

func (me *Engine) State() []Step

State is providing a slice containing the path with background and foreground nodes. It doesn't contain any internal nodes like workflow or condition. This state can be provided during initialization in the config to recover the previous state. This call is thread safe.

type Flow

type Flow struct {
	Start *Start           `json:"start"`
	Nodes map[string]*Node `json:"nodes"`
}

type InitImplFunc

type InitImplFunc func(n *Node) (NodeIF, error)

type JS

type JS struct {
	// contains filtered or unexported fields
}

func NewJSParser

func NewJSParser() *JS

func (*JS) Run

func (js *JS) Run(src interface{}) (otto.Value, error)

func (*JS) SetGlobal

func (js *JS) SetGlobal(data interface{}) error

type Looper

type Looper struct {
	// contains filtered or unexported fields
}

ensures entities are looped once to prevent from an endless loop in nested patterns

type LooperCallback

type LooperCallback func(l *Looper, node *Node) bool

type Node

type Node struct {
	ID          string                         `json:"id"`
	Name        string                         `json:"name"`
	Type        string                         `json:"type"`
	Detail      string                         `json:"detail,omitempty"`
	Data        compatability.CarriedStringMap `json:"data,omitempty"`
	Cases       []*Case                        `json:"cases,omitempty"`
	Connections []*Connection                  `json:"conns,omitempty"`
	Position    Position                       `json:"p"`
	// contains filtered or unexported fields
}

func (*Node) HierarchyPath

func (n *Node) HierarchyPath() string

func (*Node) String

func (n *Node) String() string

func (*Node) WFUniqueID

func (n *Node) WFUniqueID() string

type NodeDef

type NodeDef struct {
	//Impl is an sample instance of the node impl. The purpose of this sample is only to get reflect.Type from your implementation.
	InitImplFunc func(n *Node) (impl NodeIF, err error)
	//Background true means it is a none blocking node.
	//Background false means the node has more than one inner state that will cause multiple executions.
	Background bool
}

* In this package there are a few words about internal, background and foreground nodes. The meaning of them is here explained. background node:

A background node is not blocking the process.
When you call Next, you get a background node with Current if it is a node at the end of the workflow otherwise you will get a foreground node if no error occurred.
In the background nodes implementation there should be always returned < proceed > true if no error occurred otherwise it is configured wrong.
Which means Execute is called once if no error occurred.
Background nodes can be skipped in the Previous call to be able to get back to the last foreground node if no error occurs.
Please note, there is no detection for wrong configuration of background nodes during runtime.
If your node implementation changes and has an effect on the execution type, you must keep the background flag consistent.

foreground node:

A foreground node is blocking the process.
When you call Next usually you should get the foreground node by calling Current. Foreground nodes have states in the node implementation that causes Execute to be called more than once.
For example a form node. It has at least two states. State one is presenting the form, state two or higher is validating the form.

internal node:

Currently there are just two internal nodes, which is workflow and condition.
These nodes are handled by the engine itself, they are visible in the Stack but they can also be visible in Current.
For example if the root workflow starts with another workflow or a condition.

type NodeIF

type NodeIF interface {
	//Execute is being called when the node becomes the current target, doesn't matter whether it goes forward or backward.
	//If the node was executed before and returned proceed = false, the same instance is being used again.
	Execute(node *Node) (proceed bool, err error)
	//Remove is being called when this node is not part of the path anymore. In other words, when it doesn't exist in the State
	Remove(node *Node)
	//Close will be called on the instance before the next node is being executed or when the end is reached
	//Close is always the last called method either Execute()* -> Close() OR Execute()* -> Remove() -> Close().
	//Execute() can be called n times before Close() or Remove() as it is controlled by the node impl.
	//When it is called, the instance is released from the engine.
	Close()
}

type Position

type Position struct {
	X float64 `json:"x"`
	Y float64 `json:"y"`
}

type Stack

type Stack struct {
	Node *Node
}

type Start

type Start struct {
	NodeID   string   `json:"node"`
	Position Position `json:"p"`
}

type Step

type Step struct {
	NodeID        string `json:"nID"`
	HierarchyPath string `json:"wfID"`
	Name          string `json:"name"`
	Type          string `json:"type"`
	Detail        string `json:"detail,omitempty"`
}

type Workflow

type Workflow struct {
	Flow *Flow `json:"flow"`
}

func (*Workflow) Loop

func (me *Workflow) Loop(looper *Looper, cb LooperCallback)

Loop is making node loops easier looper keeps track of accessed entities, cb can be nil after the first call to simplify nested calls

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL