Skip to main content

Modules

Module Initialization

The kue update command is responsible for generating the module metadata cache and dependency injection configuration. This tool must be run before building the engine or whenever modules are added/modified.

Purpose

The kue update tool scans all modules in the modules/ directory, parses their Go source files, and generates:

  1. modules/meta.go: Function metadata cache for reflection-based method invocation
  2. modules/di.go: Dependency injection configuration for all transition handlers

When to Run kue update

Run kue update in the following scenarios:

ScenarioCommand
Before building the enginekue update -v
After adding a new modulekue update -v
After modifying transition methodskue update -v
After changing method signatureskue update -v

How kue update Works

┌─────────────────────────────────────────────────────────────────────┐
│ kue update Execution Flow │
├─────────────────────────────────────────────────────────────────────┤
│ 1. Initialize environment (boot.InitializeEnvironment) │
│ 2. Call GenerateMetaCache(env) │
│ 3. Locate modules path from configuration │
│ 4. Walk directory tree looking for "transitions" folders │
│ 5. Parse each .go file in transitions folders │
│ 6. Extract function metadata (names, args, return types) │
│ 7. Generate meta.go with FunctionMetadata cache │
│ 8. Generate di.go with DI container registrations │
└─────────────────────────────────────────────────────────────────────┘

GenerateMetaCache (in the kue CLI)

The core function that generates the module cache:

func GenerateMetaCache(env *boot.Environment) {
// 1. Locate modules folder
modulesPath, err := helpers.ModulesPath(env.Config.Application.ModulesPath)

// 2. Walk directory tree
filepath.WalkDir(modulesPath, func(path string, d os.DirEntry, err error) error {
// 3. Look for "transitions" subfolders
transitionsPath := filepath.Join(path, "transitions")
if stat, err := os.Stat(transitionsPath); err == nil && stat.IsDir() {
// 4. Parse each .go file
filepath.Walk(transitionsPath, func(subPath string, subInfo os.FileInfo, err error) error {
if strings.HasSuffix(subPath, ".go") {
ParseGoFile(subPath, modulesPath)
}
return nil
})
}
return nil
})

// 5. Generate output files
GenerateMetaFiles(modulesPath, "/")
}

ParseGoFile - AST Parsing

The ParseGoFile function uses Go's AST parser to extract function metadata:

func ParseGoFile(path string, modulesPath string) {
// Parse Go source file into AST
fSet := token.NewFileSet()
node, err := parser.ParseFile(fSet, path, nil, 0)

// Extract function declarations
for _, decl := range node.Decls {
funcDecl, ok := decl.(*ast.FuncDecl)

// Extract inputs (parameter names and types)
for _, field := range funcDecl.Type.Params.List {
typeStr := helpers.ExprToString(field.Type)
for _, name := range field.Names {
inputs = append(inputs, typeStr)
argNames = append(argNames, name.Name)
}
}

// Extract outputs (return types)
for _, field := range funcDecl.Type.Results.List {
typeStr := helpers.ExprToString(field.Type)
outputs = append(outputs, typeStr)
}

// Store in FunctionCache
FunctionCache[service][transition][funcDecl.Name.Name] = domain.FunctionMetadata{
Name: funcDecl.Name.Name,
NumIn: len(inputs),
NumOut: len(outputs),
ArgTypes: inputs,
ReturnTypes: outputs,
ArgNames: argNames,
ReturnNames: returnNames,
}
}
}

Generated Files

meta.go - Function Metadata Cache

// Code generated by kueinit. DO NOT EDIT.
package modules

import (
"github.com/kuetix/engine/boot"
"github.com/kuetix/engine/engine/domain/interfaces"
)

func init() {
boot.AddMetaFunctionCache(map[string]map[string]map[string]interfaces.FunctionMetadata{
"services/common": {
"response": {
"ResponseValue": {
Name: "ResponseValue",
NumIn: 3,
NumOut: 1,
ArgTypes: []string{"*workflow.WorkerSessionContext", "string", "int"},
ReturnTypes: []string{"domain.FlowStepResult"},
ArgNames: []string{"p", "message", "statusCode"},
ReturnNames: []string{"out0"},
},
},
},
})
}

di.go - Dependency Injection Configuration

// Code generated by kueinit. DO NOT EDIT.
package modules

import (
di "github.com/kuetix/container"
transitionsServicesCommon "github.com/kuetix/engine/modules/services/common/transitions"
"github.com/kuetix/engine/engine/defines"
"github.com/kuetix/engine/engine/workflow"
)

func init() {
di.Boot()
di.DependencyInjection["services/common"] = func(name string) {
di.ToResolve(defines.TransitionPrefix+"services/common"+"/"+"response", func() interface{} {
return workflow.ServiceTransitionMapping{
ServiceName: name,
Name: "response",
Impl: transitionsServicesCommon.NewResponseTransitions(),
}
})
}
}

FunctionMetadata Structure

The metadata cache stores comprehensive information about each transition method:

type FunctionMetadata struct {
Name string // Function name (e.g., "ResponseValue")
NumIn int // Number of input parameters
NumOut int // Number of return values
ArgTypes []string // Input parameter types
ReturnTypes []string // Return value types
ArgNames []string // Input parameter names
ReturnNames []string // Return value names
}

Integration with Workflow Engine

The generated cache is used by CallTransitionByName for reflection-based method invocation:

┌─────────────────┐ ┌─────────────────┐ ┌───────────────────┐
│ kueinit │────▶│ meta.go │────▶│ boot.MetaFunction │
│ (build time) │ │ di.go │ │ Cache │
└─────────────────┘ └─────────────────┘ └───────────────────┘


┌─────────────────┐ ┌─────────────────┐ ┌───────────────────┐
│ Workflow │────▶│ CallTransition │────▶│ Lookup metadata │
│ Execution │ │ ByName │ │ from cache │
└─────────────────┘ └─────────────────┘ └───────────────────┘


┌───────────────────┐
│ Invoke method │
│ via reflection │
└───────────────────┘

Build Process

The recommended build process includes running the cache generation:

# 1. Generate module cache
kue update -v

# 2. Build the engine
go build ./...

# Or use the Makefile
make build

Dependency Injection

The engine uses github.com/kuetix/container for dependency injection.

Registration

// Register a service
di.ToFetch("serviceName", serviceInstance)

// Register a factory
di.ToResolve("serviceName", func() interface{} {
return NewService()
})

// Register transitions
di.DependencyInjection["module/name"] = func(name string) {
di.ToResolve(defines.TransitionPrefix+"module/name"+"/"+"transition", func() interface{} {
return workflow.ServiceTransitionMapping{
ServiceName: name,
Name: "transition",
Impl: NewTransition(),
}
})
}

Resolution

// Fetch a service
service := di.Fetch("serviceName")

// Resolve a factory
instance := di.Resolve("serviceName")

Module System

Modules extend the engine with custom transitions and services.

Module Structure

modules/
└── my_module/
└── transitions/
└── my_transitions.go

Transition Implementation

type MyTransitions struct {
workflow.BaseServiceTransitions
}

func NewMyTransitions() *MyTransitions {
return &MyTransitions{}
}

func (t *MyTransitions) MyMethod(ctx *workflow.WorkerSessionContext) domain.FlowStepResult {
// Implementation
return domain.FlowStepResult{
Success: true,
Response: result,
StatusCode: 200,
}
}

Registration in modules/di.go

di.DependencyInjection["my_module"] = func(name string) {
di.ToResolve(defines.TransitionPrefix+"my_module"+"/"+"my_transitions", func() interface{} {
return workflow.ServiceTransitionMapping{
ServiceName: name,
Name: "my_transitions",
Impl: NewMyTransitions(),
}
})
}

Base Service Transitions

The BaseServiceTransition struct (engine/workflow/base_service_transitions.go) provides common functionality for custom transition implementations.

Structure

type BaseServiceTransition struct {
Ctx *WorkerSessionContext
}

Helper Methods

MethodDescription
SetSession(ctx)Set the worker session context
GetSession()Get the current session context
GetContext()Get the workflow context map
S()Shorthand for refresh + return context
SetResponse(response, statusCode...)Set worker response
SetStatusCode(code)Set HTTP status code
SetValue(name, value)Store value in context
GetValue(name)Retrieve value from context
Property(key)Get property from context
SetError(issue, statusCode)Set single error
SetErrors(issues, statusCode)Set multiple errors
HandleError(err, statusCode)Process and set error

Creating Custom Transitions

type MyTransitions struct {
workflow.BaseServiceTransition
}

func NewMyTransitions() interfaces.ServiceTransitions {
return &MyTransitions{}
}

func (t *MyTransitions) MyMethod(p *workflow.WorkerSessionContext) domain.FlowStepResult {
// Access base methods
ctx := t.S()

// Get property
value := t.Property("myKey")

// Set response
t.SetResponse(map[string]interface{}{"result": value}, 200)

return domain.FlowStepResult{
Success: true,
StatusCode: 200,
}
}