Documentation
¶
Overview ¶
Package workflow builds typed directed acyclic graphs of cron jobs and runs them as one cron.Job.
A Builder collects steps: typed functions (Builder.Step) or plain cron.Job values (Builder.Job). After declares a dependency on another step's Output together with the upstream result that must hold (OnSuccess, OnFailure, OnSkipped or OnComplete). Build validates names, dependencies and cycles and freezes the graph into an immutable Workflow. Execute runs ready steps with bounded parallelism, hands each step the successful outputs of its dependencies through Inputs, and reports every step's outcome in an Execution.
Index ¶
- Variables
- type Builder
- type Condition
- type ConfigError
- type Execution
- func (e *Execution) Err() error
- func (e *Execution) Error(name string) error
- func (e *Execution) Errors() map[string]error
- func (e *Execution) Get[T any](output Output[T]) (T, bool)
- func (e *Execution) Result(name string) (Result, bool)
- func (e *Execution) Results() map[string]Result
- func (e *Execution) Step(name string) (StepReport, bool)
- func (e *Execution) Steps() map[string]StepReport
- type Inputs
- type Option
- type Output
- type Result
- type StepOption
- type StepReport
- type Unit
- type Workflow
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrDuplicateStep reports two steps with the same name. ErrDuplicateStep = errors.New("workflow: duplicate step") // ErrDuplicateDep reports the same dependency declared twice on one step. ErrDuplicateDep = errors.New("workflow: duplicate dependency") // ErrUnknownDep reports a dependency on a step that is not in the graph, // including an Output taken from another Builder. ErrUnknownDep = errors.New("workflow: unknown dependency") // ErrCycle reports a dependency cycle; the message lists its path. ErrCycle = errors.New("workflow: dependency cycle") // ErrNilJob reports a step added with a nil function or cron.Job. ErrNilJob = errors.New("workflow: step has no job") // ErrInvalidName reports an empty step name or one with surrounding // whitespace. ErrInvalidName = errors.New("workflow: invalid step name") // ErrInvalidOption is wrapped when a Builder or step option is nil or // rejects its argument. ErrInvalidOption = errors.New("workflow: invalid option") // ErrBuilderFrozen is returned by Build when steps were added after an // earlier Build. ErrBuilderFrozen = errors.New("workflow: builder is frozen") // ErrNilContext is reported by Execution.Err when Execute received a nil // context; every step is skipped. ErrNilContext = errors.New("workflow: nil context") )
Sentinel errors reported by Build and Execute; match them with errors.Is.
Functions ¶
This section is empty.
Types ¶
type Builder ¶ added in v0.5.3
type Builder struct {
// contains filtered or unexported fields
}
Builder incrementally constructs one Workflow. Errors from options and steps are collected and reported by Build, so a sequence of Step calls needs no error handling. Build freezes the Builder: later Step and Job calls are ignored and make every subsequent Build return ErrBuilderFrozen. Builder is not safe for concurrent use; its zero value is ready to use.
Example ¶
ExampleBuilder wires two typed steps; the second reads the first's output.
package main
import (
"context"
"errors"
"fmt"
"github.com/libtnb/cron/workflow"
)
func main() {
b := workflow.New(workflow.WithMaxParallelism(4))
fetch := b.Step[int]("fetch", func(ctx context.Context, _ workflow.Inputs) (int, error) {
return 42, nil
})
store := b.Step[string]("store", func(ctx context.Context, in workflow.Inputs) (string, error) {
n, ok := in.Get(fetch)
if !ok {
return "", errors.New("fetch output unavailable")
}
return fmt.Sprintf("stored %d", n), nil
}, workflow.After(fetch, workflow.OnSuccess))
wf, err := b.Build()
if err != nil {
fmt.Println("build:", err)
return
}
exec := wf.Execute(context.Background())
result, _ := exec.Get(store)
fmt.Println(result)
fmt.Println(exec.Results()["fetch"], exec.Results()["store"], exec.Err())
}
Output: stored 42 success success <nil>
Example (OnFailure) ¶
ExampleBuilder_onFailure runs a fallback only when the primary step fails.
package main
import (
"context"
"errors"
"fmt"
"github.com/libtnb/cron"
"github.com/libtnb/cron/workflow"
)
func main() {
b := workflow.New()
primary := b.Job("primary", cron.JobFunc(func(ctx context.Context) error {
return errors.New("upstream down")
}))
b.Job("fallback", cron.JobFunc(func(ctx context.Context) error {
fmt.Println("fallback ran")
return nil
}), workflow.After(primary, workflow.OnFailure))
b.Job("report", cron.JobFunc(func(ctx context.Context) error {
fmt.Println("report ran")
return nil
}), workflow.After(primary, workflow.OnSuccess))
exec := b.MustBuild().Execute(context.Background())
fmt.Println(exec.Results()["fallback"], exec.Results()["report"])
fmt.Println(exec.Err())
}
Output: fallback ran success skipped upstream down
func New ¶
New returns an empty Builder configured by opts. Invalid options are reported by Build, not here.
func (*Builder) Build ¶ added in v0.5.3
Build validates the graph, freezes the Builder and returns an immutable Workflow. Repeated calls return the same result. It returns the joined option errors (wrapping ErrInvalidOption), a *ConfigError wrapping ErrNilJob, ErrInvalidName, ErrDuplicateStep, ErrUnknownDep or ErrDuplicateDep, ErrCycle with the cycle's path, or ErrBuilderFrozen when steps were added after an earlier Build.
func (*Builder) Job ¶ added in v0.5.3
Job adds a cron.Job step whose Output type is Unit. It follows the same rules as Step.
func (*Builder) MustBuild ¶ added in v0.5.3
MustBuild is Build that panics on error, for graphs fixed at build time.
func (*Builder) Step ¶ added in v0.5.3
func (b *Builder) Step[T any]( name string, fn func(context.Context, Inputs) (T, error), opts ...StepOption, ) Output[T]
Step adds a step computing a T and returns its Output for use with After and Get. Steps run in dependency order, not registration order. name must be unique, non-empty and free of surrounding whitespace (Build reports ErrDuplicateStep or ErrInvalidName); a nil fn is reported as ErrNilJob. A panic in fn is recovered into a failure result.
type Condition ¶
type Condition uint8
Condition selects which upstream Result satisfies a dependency declared with After.
const ( // OnSuccess runs the step only if the dependency succeeded. OnSuccess Condition // OnFailure runs the step only if the dependency failed or panicked. OnFailure // OnSkipped runs the step only if the dependency was skipped. OnSkipped // OnComplete runs the step whatever the dependency's result. OnComplete )
type ConfigError ¶
ConfigError identifies the step, and for dependency faults the dependency, involved in an invalid graph. Err is one of ErrDuplicateStep, ErrNilJob, ErrInvalidName, ErrUnknownDep or ErrDuplicateDep.
func (*ConfigError) Error ¶
func (e *ConfigError) Error() string
Error names the step and, for dependency faults, the dependency.
func (*ConfigError) Unwrap ¶
func (e *ConfigError) Unwrap() error
Unwrap exposes the sentinel to errors.Is.
type Execution ¶
type Execution struct {
ID uuid.UUID // time-ordered (version 7), unique per run
StartedAt time.Time
Duration time.Duration
// contains filtered or unexported fields
}
Execution reports one completed Workflow run. It is immutable and safe for concurrent reads; the accessors return copies.
func (*Execution) Err ¶
Err joins the step errors in registration order, or returns nil when no step failed. A step skipped because the context was cancelled contributes the cancellation cause; one skipped for an unmet condition contributes nothing. A nil ctx passed to Execute yields ErrNilContext.
func (*Execution) Error ¶ added in v0.5.3
Error returns the named step's error, or nil for success, a skip without cause, or an unknown name.
func (*Execution) Get ¶ added in v0.5.3
Get returns the typed output of a successful step. ok is false when the step failed or was skipped, when output belongs to another graph, or for the zero Output.
func (*Execution) Result ¶ added in v0.5.3
Result returns the named step's Result; ok is false for an unknown name.
func (*Execution) Step ¶ added in v0.5.3
func (e *Execution) Step(name string) (StepReport, bool)
Step returns the named step's report; ok is false for an unknown name.
func (*Execution) Steps ¶ added in v0.3.0
func (e *Execution) Steps() map[string]StepReport
Steps returns a copy of every step's report keyed by name.
type Inputs ¶ added in v0.3.0
type Inputs struct {
// contains filtered or unexported fields
}
Inputs gives a running step the outputs of its declared dependencies. Only successful dependencies carry a value: Get reports ok == false for a dependency that failed or was skipped, for a step the caller did not declare with After, and for an Output from another graph.
type Option ¶ added in v0.5.3
type Option func(*builderConfig) error
Option configures a Builder; see New.
func WithMaxParallelism ¶ added in v0.5.3
WithMaxParallelism limits how many steps run at the same time. The default is 32; a non-positive limit fails Build with ErrInvalidOption.
type Output ¶ added in v0.5.3
type Output[T any] struct { // contains filtered or unexported fields }
Output identifies one step's typed output within its graph. Pass it to After to declare a dependency and to Inputs.Get or Execution.Get to read the value. The zero Output belongs to no graph and is rejected everywhere.
type Result ¶
type Result uint8
Result is a step outcome as reported by Execution.
const ( // ResultPending is a step's state before it completes; it never appears // in a finished Execution. ResultPending Result = iota // ResultSuccess reports that the step returned no error. ResultSuccess // ResultFailure reports that the step returned an error or panicked. ResultFailure // ResultSkipped reports that the step did not run because a dependency // condition was not met or the context was already cancelled. ResultSkipped )
type StepOption ¶ added in v0.5.3
type StepOption func(*step) error
StepOption configures one step at Builder.Step or Builder.Job time. Options are applied in order; failures are reported by Build.
func After ¶
func After[T any](output Output[T], when Condition) StepOption
After declares that the step runs only after output's step completes with a result matching when. A step waits for all its dependencies and is skipped if any condition fails. The zero Output or an unknown Condition fails Build with ErrInvalidOption; declaring the same dependency twice fails it with ErrDuplicateDep.
func WithRetry ¶ added in v0.5.3
func WithRetry(policy cron.RetryPolicy) StepOption
WithRetry re-runs one step on error according to policy (see cron.RetryPolicy). A policy with negative delays or a jitter fraction outside [0, 1] fails Build with ErrInvalidOption.
func WithTimeout ¶ added in v0.5.3
func WithTimeout(timeout time.Duration) StepOption
WithTimeout caps one step run; the step context is cancelled with cron.ErrJobTimeout as the cause. Zero disables the timeout; a negative timeout fails Build with ErrInvalidOption.
type StepReport ¶ added in v0.3.0
type StepReport struct {
Result Result
Err error // step error, or the cancellation cause for a step skipped by a cancelled context
StartedAt time.Time // zero for skipped steps
Duration time.Duration // zero for skipped steps
// contains filtered or unexported fields
}
StepReport is one step's outcome within an Execution.
type Unit ¶ added in v0.5.3
type Unit struct{}
Unit is the output type of steps added with Builder.Job; it carries no data.
type Workflow ¶
type Workflow struct {
// contains filtered or unexported fields
}
Workflow is an immutable DAG produced by Builder.Build. It implements cron.Job, so it can be registered with Cron.Add or Cron.AddSchedule, and is safe for concurrent use: every Run or Execute is an independent execution.
func (*Workflow) Execute ¶ added in v0.5.3
Execute runs the DAG once and blocks until every step has completed or been skipped; at most the configured number of steps run at the same time. A step is skipped when a dependency condition is not met or when ctx is already cancelled by the time the step becomes ready; steps already running observe the cancellation through their context. A nil ctx skips every step and reports ErrNilContext.
func (*Workflow) Run ¶
Run executes the DAG once and returns Execution.Err, which makes a Workflow a cron.Job.
func (*Workflow) WithOnComplete ¶
WithOnComplete returns a copy of w that calls cb with the finished Execution, on the calling goroutine, before Execute returns. w itself is unchanged.