Documentation
¶
Index ¶
- Variables
- func DAGEdgesNWithReport[T context.Context](limit int, connections ...DAGConnection[T]) func(ctx T) (*DAGReport, error)
- func DAGEdgesToDOT[T context.Context](connections ...DAGConnection[T]) (string, error)
- func DAGEdgesToMermaid[T context.Context](connections ...DAGConnection[T]) (string, error)
- func DAGEdgesWithReport[T context.Context](connections ...DAGConnection[T]) func(ctx T) (*DAGReport, error)
- func DAGNWithReport[T context.Context](limit int, nodes ...*DAGNode[T]) func(ctx T) (*DAGReport, error)
- func DAGToDOT[T context.Context](nodes ...*DAGNode[T]) (string, error)
- func DAGToMermaid[T context.Context](nodes ...*DAGNode[T]) (string, error)
- func DAGWithReport[T context.Context](nodes ...*DAGNode[T]) func(ctx T) (*DAGReport, error)
- func Pipe2[T context.Context, A, B, C any](f1 func(ctx T, a A) (B, error), f2 func(ctx T, b B) (C, error)) func(ctx T, a A) (C, error)
- func Pipe3[T context.Context, A, B, C, D any](f1 func(ctx T, a A) (B, error), f2 func(ctx T, b B) (C, error), ...) func(ctx T, a A) (D, error)
- type DAGConnection
- type DAGEdgeBuilder
- type DAGNode
- func (n *DAGNode[T]) After(deps ...string) *DAGNode[T]
- func (n *DAGNode[T]) Unless(predicate func(ctx T) bool) *DAGNode[T]
- func (n *DAGNode[T]) When(predicate func(ctx T) bool) *DAGNode[T]
- func (n *DAGNode[T]) WithCatch(handler func(ctx T, err error) error) *DAGNode[T]
- func (n *DAGNode[T]) WithFallback(fallback Step[T]) *DAGNode[T]
- func (n *DAGNode[T]) WithRecover() *DAGNode[T]
- func (n *DAGNode[T]) WithRetry(attempts int, delay ...time.Duration) *DAGNode[T]
- func (n *DAGNode[T]) WithTimeout(d time.Duration) *DAGNode[T]
- type DAGPlan
- func (p *DAGPlan[T]) ExecNWithReport(limit int, ctx T) (*DAGReport, error)
- func (p *DAGPlan[T]) ExecWithReport(ctx T) (*DAGReport, error)
- func (p *DAGPlan[T]) Step() Step[T]
- func (p *DAGPlan[T]) StepN(limit int) Step[T]
- func (p *DAGPlan[T]) StepNWithReport(limit int) func(ctx T) (*DAGReport, error)
- func (p *DAGPlan[T]) StepWithReport() func(ctx T) (*DAGReport, error)
- func (p *DAGPlan[T]) ToDOT() (string, error)
- func (p *DAGPlan[T]) ToMermaid() (string, error)
- func (p *DAGPlan[T]) Validate() error
- type DAGReport
- type Middleware
- type NodeReport
- type NodeStatus
- type Step
- func Branch[T context.Context](condition func(ctx T) bool, ifBranch, elseBranch Step[T]) Step[T]
- func Chunk[T context.Context, V any](seq iter.Seq[V], size int, step func(ctx T, batch []V) error) Step[T]
- func Chunk2[T context.Context, K, V any](seq iter.Seq2[K, V], size int, step func(ctx T, keys []K, vals []V) error) Step[T]
- func DAG[T context.Context](nodes ...*DAGNode[T]) Step[T]
- func DAGEdges[T context.Context](connections ...DAGConnection[T]) Step[T]
- func DAGEdgesN[T context.Context](limit int, connections ...DAGConnection[T]) Step[T]
- func DAGN[T context.Context](limit int, nodes ...*DAGNode[T]) Step[T]
- func Each[T context.Context, V any](seq iter.Seq[V], step func(ctx T, item V) error) Step[T]
- func Each2[T context.Context, K, V any](seq iter.Seq2[K, V], step func(ctx T, key K, val V) error) Step[T]
- func Go[T context.Context](steps ...Step[T]) Step[T]
- func GoN[T context.Context](limit int, steps ...Step[T]) Step[T]
- func Once[T context.Context](step Step[T]) Step[T]
- func Pipe[T context.Context, In, Out any](fn func(ctx T, in In) (Out, error), get func(ctx T) In, ...) Step[T]
- func PipeSeq[T context.Context, In, Out any](seq iter.Seq[In], transform func(ctx T, item In) (Out, error), ...) Step[T]
- func PipeSeq2[T context.Context, K, V, Out any](seq iter.Seq2[K, V], transform func(ctx T, key K, val V) (Out, error), ...) Step[T]
- func Race[T context.Context](steps ...Step[T]) Step[T]
- func Seq[T context.Context](steps ...Step[T]) Step[T]
- func (s Step[T]) Branch(condition func(ctx T) bool, ifBranch, elseBranch Step[T]) Step[T]
- func (s Step[T]) Catch(handler func(ctx T, err error) error) Step[T]
- func (s Step[T]) Exec(ctx T) error
- func (s Step[T]) Fallback(fallback Step[T]) Step[T]
- func (s Step[T]) Go(steps ...Step[T]) Step[T]
- func (s Step[T]) GoN(limit int, steps ...Step[T]) Step[T]
- func (s Step[T]) Once() Step[T]
- func (s Step[T]) Race(steps ...Step[T]) Step[T]
- func (s Step[T]) Recover() Step[T]
- func (s Step[T]) Retry(attempts int, delay time.Duration) Step[T]
- func (s Step[T]) Then(steps ...Step[T]) Step[T]
- func (s Step[T]) Timeout(d time.Duration) Step[T]
- func (s Step[T]) Unless(predicate func(ctx T) bool) Step[T]
- func (s Step[T]) When(predicate func(ctx T) bool) Step[T]
- func (s Step[T]) Wrap(middlewares ...Middleware[T]) Step[T]
Examples ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var ( ErrDAGCycle = errors.New("cycle detected in DAG") ErrDAGUnknownDependency = errors.New("unknown dependency in DAG") ErrDAGDuplicateNode = errors.New("duplicate node name in DAG") ErrDAGNilNode = errors.New("nil node in DAG") ErrDAGEmptyNodeName = errors.New("empty node name in DAG") )
Functions ¶
func DAGEdgesNWithReport ¶ added in v0.6.0
func DAGEdgesToDOT ¶ added in v0.4.0
func DAGEdgesToDOT[T context.Context](connections ...DAGConnection[T]) (string, error)
func DAGEdgesToMermaid ¶ added in v0.4.0
func DAGEdgesToMermaid[T context.Context](connections ...DAGConnection[T]) (string, error)
func DAGEdgesWithReport ¶ added in v0.6.0
func DAGEdgesWithReport[T context.Context](connections ...DAGConnection[T]) func(ctx T) (*DAGReport, error)
func DAGNWithReport ¶ added in v0.6.0
func DAGToDOT ¶ added in v0.4.0
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
user := flow.Node("user", func(ctx context.Context) error { return nil })
payment := flow.Node("payment", func(ctx context.Context) error { return nil }).After("user")
dot, err := flow.DAGToDOT(user, payment)
if err != nil {
panic(err)
}
fmt.Println(len(dot) > 0)
}
Output:
func DAGToMermaid ¶ added in v0.4.0
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
user := flow.Node("user", func(ctx context.Context) error { return nil })
payment := flow.Node("payment", func(ctx context.Context) error { return nil }).After("user")
mermaid, err := flow.DAGToMermaid(user, payment)
if err != nil {
panic(err)
}
fmt.Println(len(mermaid) > 0)
}
Output:
func DAGWithReport ¶ added in v0.6.0
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
user := flow.Node("user", func(ctx context.Context) error { return nil })
payment := flow.Node("payment", func(ctx context.Context) error { return nil }).After("user")
exec := flow.DAGWithReport(user, payment)
report, err := exec(context.Background())
if err != nil {
panic(err)
}
for _, n := range report.Nodes {
fmt.Printf("%s: %s\n", n.Name, n.Status)
}
}
Output:
Types ¶
type DAGConnection ¶
type DAGEdgeBuilder ¶
func (DAGEdgeBuilder[T]) To ¶
func (b DAGEdgeBuilder[T]) To(to ...Step[T]) DAGConnection[T]
type DAGNode ¶
func (*DAGNode[T]) WithFallback ¶ added in v0.6.0
func (*DAGNode[T]) WithRecover ¶ added in v0.6.0
type DAGPlan ¶ added in v0.4.0
func NewDAG ¶ added in v0.4.0
Example ¶
package main
import (
"context"
"github.com/ntkwan/go-flow"
)
func main() {
user := flow.Node("user", func(ctx context.Context) error { return nil })
payment := flow.Node("payment", func(ctx context.Context) error { return nil }).After("user")
plan := flow.NewDAG(user, payment)
if err := plan.Validate(); err != nil {
panic(err)
}
step := plan.Step()
_ = step(context.Background())
}
Output:
func NewDAGEdges ¶ added in v0.4.0
func NewDAGEdges[T context.Context](connections ...DAGConnection[T]) (*DAGPlan[T], error)
func (*DAGPlan[T]) ExecNWithReport ¶ added in v0.6.0
func (*DAGPlan[T]) ExecWithReport ¶ added in v0.6.0
func (*DAGPlan[T]) StepNWithReport ¶ added in v0.6.0
func (*DAGPlan[T]) StepWithReport ¶ added in v0.6.0
type DAGReport ¶ added in v0.6.0
type DAGReport struct {
Duration time.Duration
StartTime time.Time
EndTime time.Time
Nodes []NodeReport
// contains filtered or unexported fields
}
func (*DAGReport) Failed ¶ added in v0.6.0
func (r *DAGReport) Failed() []NodeReport
func (*DAGReport) Node ¶ added in v0.6.0
func (r *DAGReport) Node(name string) *NodeReport
func (*DAGReport) Skipped ¶ added in v0.6.0
func (r *DAGReport) Skipped() []NodeReport
func (*DAGReport) Successful ¶ added in v0.6.0
func (r *DAGReport) Successful() []NodeReport
type NodeReport ¶ added in v0.6.0
type NodeStatus ¶ added in v0.6.0
type NodeStatus string
const ( NodeStatusSuccess NodeStatus = "SUCCESS" NodeStatusFailed NodeStatus = "FAILED" NodeStatusSkipped NodeStatus = "SKIPPED" )
type Step ¶
func Branch ¶ added in v0.3.0
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
type RequestContext struct {
context.Context
IsAdmin bool
}
adminStep := func(ctx *RequestContext) error {
fmt.Println("Admin flow")
return nil
}
userStep := func(ctx *RequestContext) error {
fmt.Println("User flow")
return nil
}
route := flow.Branch(
func(ctx *RequestContext) bool { return ctx.IsAdmin },
adminStep,
userStep,
)
ctx := &RequestContext{Context: context.Background(), IsAdmin: true}
_ = route(ctx)
}
Output:
func Chunk ¶
func Chunk[T context.Context, V any](seq iter.Seq[V], size int, step func(ctx T, batch []V) error) Step[T]
Example ¶
package main
import (
"context"
"fmt"
"slices"
"github.com/ntkwan/go-flow"
)
func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7}
batchProcess := flow.Chunk(slices.Values(numbers), 3, func(ctx context.Context, batch []int) error {
fmt.Printf("Batch of %d items: %v\n", len(batch), batch)
return nil
})
_ = batchProcess(context.Background())
}
Output:
func DAG ¶
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
user := flow.Node("user", func(ctx context.Context) error {
fmt.Println("User loaded")
return nil
})
inventory := flow.Node("inventory", func(ctx context.Context) error {
fmt.Println("Inventory reserved")
return nil
})
payment := flow.Node("payment", func(ctx context.Context) error {
fmt.Println("Payment charged")
return nil
}).After("user", "inventory")
graph := flow.DAG(user, inventory, payment)
_ = graph(context.Background())
}
Output:
Example (Conditional) ¶
package main
import (
"context"
"github.com/ntkwan/go-flow"
)
func main() {
type userContext struct {
context.Context
isPremium bool
}
baseTask := flow.Node("base", func(ctx *userContext) error { return nil })
bonusTask := flow.Node("bonus", func(ctx *userContext) error { return nil }).
After("base").
When(func(ctx *userContext) bool { return ctx.isPremium })
graph := flow.DAG(baseTask, bonusTask)
_ = graph(&userContext{Context: context.Background(), isPremium: false})
}
Output:
func DAGEdges ¶
func DAGEdges[T context.Context](connections ...DAGConnection[T]) Step[T]
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
fetchUser := func(ctx context.Context) error {
fmt.Println("Fetch user")
return nil
}
chargePayment := func(ctx context.Context) error {
fmt.Println("Charge payment")
return nil
}
graph := flow.DAGEdges(
flow.From(fetchUser).To(chargePayment),
)
_ = graph(context.Background())
}
Output:
func DAGEdgesN ¶
func DAGEdgesN[T context.Context](limit int, connections ...DAGConnection[T]) Step[T]
func DAGN ¶
Example ¶
package main
import (
"context"
"github.com/ntkwan/go-flow"
)
func main() {
n1 := flow.Node("task1", func(ctx context.Context) error { return nil })
n2 := flow.Node("task2", func(ctx context.Context) error { return nil })
n3 := flow.Node("task3", func(ctx context.Context) error { return nil })
boundedGraph := flow.DAGN(2, n1, n2, n3)
_ = boundedGraph(context.Background())
}
Output:
func Each ¶
Example ¶
package main
import (
"context"
"fmt"
"slices"
"github.com/ntkwan/go-flow"
)
func main() {
items := slices.Values([]string{"apple", "banana", "cherry"})
process := flow.Each(items, func(ctx context.Context, item string) error {
fmt.Println("Processing:", item)
return nil
})
_ = process(context.Background())
}
Output:
func Go ¶
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
stepA := func(ctx context.Context) error {
fmt.Println("Task A")
return nil
}
stepB := func(ctx context.Context) error {
fmt.Println("Task B")
return nil
}
parallel := flow.Go(stepA, stepB)
_ = parallel(context.Background())
}
Output:
func GoN ¶
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
tasks := make([]flow.Step[context.Context], 5)
for i := range tasks {
idx := i
tasks[i] = func(ctx context.Context) error {
fmt.Printf("Worker task %d\n", idx)
return nil
}
}
bounded := flow.GoN(2, tasks...)
_ = bounded(context.Background())
}
Output:
func Once ¶
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
initDB := flow.Once(func(ctx context.Context) error {
fmt.Println("Database initialized once")
return nil
})
step1 := flow.Seq(initDB, func(ctx context.Context) error { return nil })
step2 := flow.Seq(initDB, func(ctx context.Context) error { return nil })
pipeline := flow.Go(step1, step2)
_ = pipeline(context.Background())
}
Output:
func Pipe ¶ added in v0.3.0
func Pipe[T context.Context, In, Out any]( fn func(ctx T, in In) (Out, error), get func(ctx T) In, set func(ctx T, out Out), ) Step[T]
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
type State struct {
Count int
}
st := &State{Count: 5}
doubleCount := flow.Pipe(
func(ctx context.Context, in int) (int, error) {
return in * 2, nil
},
func(ctx context.Context) int {
return st.Count
},
func(ctx context.Context, out int) {
st.Count = out
},
)
_ = doubleCount(context.Background())
fmt.Printf("Result: %d\n", st.Count)
}
Output:
func PipeSeq ¶ added in v0.3.0
func PipeSeq[T context.Context, In, Out any]( seq iter.Seq[In], transform func(ctx T, item In) (Out, error), sink func(ctx T, item Out) error, ) Step[T]
Example ¶
package main
import (
"context"
"fmt"
"slices"
"github.com/ntkwan/go-flow"
)
func main() {
numbers := slices.Values([]int{1, 2, 3})
stream := flow.PipeSeq(
numbers,
func(ctx context.Context, in int) (string, error) {
return fmt.Sprintf("val-%d", in*10), nil
},
func(ctx context.Context, out string) error {
fmt.Println(out)
return nil
},
)
_ = stream(context.Background())
}
Output:
func Race ¶
Example ¶
package main
import (
"context"
"fmt"
"time"
"github.com/ntkwan/go-flow"
)
func main() {
server1 := func(ctx context.Context) error {
time.Sleep(10 * time.Millisecond)
fmt.Println("Server 1 responded")
return nil
}
server2 := func(ctx context.Context) error {
fmt.Println("Server 2 responded fastest")
return nil
}
fastest := flow.Race(server1, server2)
_ = fastest(context.Background())
}
Output:
func Seq ¶
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
step1 := func(ctx context.Context) error {
fmt.Println("Step 1")
return nil
}
step2 := func(ctx context.Context) error {
fmt.Println("Step 2")
return nil
}
pipeline := flow.Seq(step1, step2)
_ = pipeline(context.Background())
}
Output:
func (Step[T]) Fallback ¶
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
failingPrimary := flow.Step[context.Context](func(ctx context.Context) error {
return fmt.Errorf("primary service down")
})
backupService := flow.Step[context.Context](func(ctx context.Context) error {
fmt.Println("Backup service handled request")
return nil
})
protected := failingPrimary.Fallback(backupService)
_ = protected.Exec(context.Background())
}
Output:
func (Step[T]) Retry ¶
Example ¶
package main
import (
"context"
"fmt"
"time"
"github.com/ntkwan/go-flow"
)
func main() {
attempts := 0
flaky := flow.Step[context.Context](func(ctx context.Context) error {
attempts++
if attempts < 3 {
return fmt.Errorf("temporary failure %d", attempts)
}
fmt.Println("Succeeded on attempt 3")
return nil
})
resilient := flaky.Retry(3, 10*time.Millisecond)
_ = resilient.Exec(context.Background())
}
Output:
func (Step[T]) Then ¶
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
s1 := flow.Step[context.Context](func(ctx context.Context) error {
fmt.Println("First")
return nil
})
s2 := flow.Step[context.Context](func(ctx context.Context) error {
fmt.Println("Second")
return nil
})
chained := s1.Then(s2)
_ = chained.Exec(context.Background())
}
Output:
func (Step[T]) Timeout ¶
Example ¶
package main
import (
"context"
"fmt"
"time"
"github.com/ntkwan/go-flow"
)
func main() {
slow := flow.Step[context.Context](func(ctx context.Context) error {
time.Sleep(50 * time.Millisecond)
return nil
})
timed := slow.Timeout(10 * time.Millisecond)
err := timed.Exec(context.Background())
fmt.Println("Error:", err != nil)
}
Output:
func (Step[T]) When ¶
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
type OrderContext struct {
context.Context
IsVIP bool
}
vipGift := flow.Step[*OrderContext](func(ctx *OrderContext) error {
fmt.Println("VIP gift applied")
return nil
}).When(func(ctx *OrderContext) bool {
return ctx.IsVIP
})
ctx := &OrderContext{Context: context.Background(), IsVIP: true}
_ = vipGift.Exec(ctx)
}
Output:
func (Step[T]) Wrap ¶
func (s Step[T]) Wrap(middlewares ...Middleware[T]) Step[T]
Example ¶
package main
import (
"context"
"fmt"
"github.com/ntkwan/go-flow"
)
func main() {
base := flow.Step[context.Context](func(ctx context.Context) error {
fmt.Println("Core logic")
return nil
})
loggingMiddleware := func(next flow.Step[context.Context]) flow.Step[context.Context] {
return func(ctx context.Context) error {
fmt.Println("Before step")
err := next(ctx)
fmt.Println("After step")
return err
}
}
wrapped := base.Wrap(loggingMiddleware)
_ = wrapped.Exec(context.Background())
}
Output:
Click to show internal directories.
Click to hide internal directories.