A Task is a collection of Actions that execute sequentially. Tasks manage execution flow, error handling, parameter validation, and output storage.
type Task struct {
ID string
RunID string // auto-generated per execution
Name string
Actions []ActionWrapper
Logger *slog.Logger
TotalTime time.Duration
CompletedTasks int
// Optional: build a structured result at the end of execution
ResultBuilder func(ctx *TaskContext) (interface{}, error)
}A TaskContext is passed to a task's ResultBuilder function. It provides the task ID, access to the shared GlobalContext, and a logger.
type TaskContext struct {
TaskID string
GlobalContext *GlobalContext
Logger *slog.Logger
}An Action represents a single operation (file I/O, Docker command, system call). Actions implement the ActionInterface with Before/Execute/After lifecycle hooks.
type ActionInterface interface {
BeforeExecute(ctx context.Context) error
Execute(ctx context.Context) error
AfterExecute(ctx context.Context) error
GetOutput() interface{}
}ActionWrapper is the interface tasks use to run actions, access metadata, and retrieve output.
type ActionWrapper interface {
Execute(ctx context.Context) error
GetID() string
GetName() string
GetOutput() interface{}
GetDuration() time.Duration
GetLogger() *slog.Logger
SetID(string)
}TaskManager orchestrates multiple tasks, manages shared GlobalContext, and provides task lifecycle control (run, stop, wait).
Fixed values known at task creation time.
engine.StaticParameter{Value: "/path/to/file"}Reference outputs from previous actions within the same task.
engine.ActionOutput("read-action")
engine.ActionOutputField("read-action", "content")Reference outputs from other tasks using the global context.
engine.TaskOutput("build-task")
engine.TaskOutputField("build-task", "imageID")Use rich results from actions that implement ResultProvider.
engine.ActionResult("download-artifact")
engine.ActionResultField("download-artifact", "checksum")Use rich results from tasks that implement ResultProvider or define a ResultBuilder.
engine.TaskResult("preflight")
engine.TaskResultField("preflight", "UpdateMode")All built-in actions use a builder pattern. Constructors return a builder (or the action itself) that accepts parameters via a WithParameters method, which returns a ready-to-use *Action[T].
// 1. Create the action builder
action, err := file.NewWriteFileAction(logger).WithParameters(
engine.StaticParameter{Value: "/path/to/file"},
engine.StaticParameter{Value: []byte("content")},
true, // overwrite
nil,
)
if err != nil {
return err
}
// 2. Optionally set a custom ID (default is generated from the action name)
action.ID = "write-config"
// 3. Add to a task
task.Actions = append(task.Actions, action)The common package provides three reusable building blocks to eliminate boilerplate in custom actions:
| Type | Purpose |
|---|---|
BaseConstructor[T] |
Provides WrapAction() to produce an *Action[T] without repeating struct literal setup |
ParameterResolver |
Embedded in action structs; handles GlobalContext extraction and typed parameter resolution |
OutputBuilder |
Embedded in action structs; provides consistent map[string]interface{} output construction |
Embed them in your action struct and initialize in the constructor:
type MyAction struct {
task_engine.BaseAction
common.ParameterResolver
common.OutputBuilder
// your fields
}
func NewMyAction(logger *slog.Logger) *MyAction {
return &MyAction{
BaseAction: task_engine.NewBaseAction(logger),
ParameterResolver: *common.NewParameterResolver(logger),
OutputBuilder: *common.NewOutputBuilder(logger),
}
}- Task Creation: Actions are created via builders and added to a task's
Actionsslice asActionWrappervalues - Parameter Validation: Before execution begins,
validateParameters()checks for empty or duplicate action IDs - Action Execution: Each action runs
BeforeExecute → Execute → AfterExecutehooks with a context that embeds theGlobalContext - Output Storage: After each action, its output and any
ResultProviderresult are stored in theGlobalContext - Result Building: After all actions complete, the optional
ResultBuilderis called with aTaskContext - Task Output Storage: Task output and result are stored in the
GlobalContextfor cross-task reference - Error Handling: Tasks stop on first error;
ErrPrerequisiteNotMetsignals a graceful abort
The GlobalContext maintains:
ActionOutputs: Results from completed actions (keyed by action ID)ActionResults: Rich results from actions implementingResultProviderTaskOutputs: Results from completed tasks (keyed by task ID), auto-populated with execution metadataTaskResults: Rich results from tasks implementingResultProvider(or usingResultBuilder)
Context is shared across tasks via the TaskManager and embedded into each action's execution context under GlobalContextKey.
- Prerequisites: Return
ErrPrerequisiteNotMetto gracefully abort tasks - Execution Errors: Stop task execution and return error details
- Context Cancellation: Respect context cancellation for timeouts and graceful shutdown
- Duplicate IDs: Detected at validation time before execution begins
- Mocks: Complete mock implementations for all interfaces (
testing/mocks/) - Testable Manager: Enhanced
TaskManagerwith testing hooks (testing/) - Performance Testing: Built-in benchmarking and load testing utilities (
testing/)