Worker Groups

kontinue resources (Functions, Executions) are scoped to Kubernetes namespaces by default. Worker groups allow you to run multiple independent workers within the same namespace, each handling different sets of functions.

Why Worker Groups?

Use worker groups when you need to:

  • Run separate worker deployments for different teams or services in the same namespace
  • Isolate function sets with different resource requirements or scaling needs
  • Deploy multiple versions of the same function for testing or canary releases

Configuring Worker Groups

Specify the worker group when initializing a worker:

w, err := worker.New(worker.Options{
    Namespace: "infra",
    Group:     "deployments",
})
if err != nil {
    log.Fatal(err)
}

The Group field is required and has no default value. All functions registered with this worker will be scoped to the deployments worker group.

How It Works

When a worker starts, it:

  1. Registers its functions with the kontinue.cloud/worker-group label
  2. Only processes Executions that match its worker group
  3. Labels all created resources (Executions, Suspensions, Jobs) with its group
apiVersion: kontinue.cloud/v1alpha1
kind: Function
metadata:
  name: deploy-service
  labels:
    kontinue.cloud/worker-group: deployments
spec:
  name: deploy-service
  workerGroup: deployments

Multiple Workers in One Namespace

Deploy separate workers for different concerns:

// deployments-worker/main.go
w, _ := worker.New(worker.Options{
    Namespace: "infra",
    Group:     "deployments",
})
worker.RegisterFunction(w, "deploy-service", DeployService, nil)
worker.RegisterFunction(w, "rollback-service", RollbackService, nil)
// provisioning-worker/main.go
w, _ := worker.New(worker.Options{
    Namespace: "infra",
    Group:     "provisioning",
})
worker.RegisterFunction(w, "provision-cluster", ProvisionCluster, nil)
worker.RegisterFunction(w, "provision-database", ProvisionDatabase, nil)

Each worker only sees and processes its own functions and executions.

Cross-Group Child Executions

Executions can spawn child executions in other worker groups within the same namespace. The child execution is handled by the appropriate worker group:

func ReleaseWorkflow(ktx *kontinue.ExecutionContext, args *ReleaseArgs) (*ReleaseResult, error) {
    // This execution runs in the "releases" worker group

    // Spawn a child in the "testing" worker group
    _, err := kontinue.Execute[TestResult](ktx, "run-integration-tests", &TestArgs{
        Version: args.Version,
        Env:     "staging",
    }, nil)
    if err != nil {
        return nil, err
    }

    // Spawn a child in the "deployments" worker group
    _, err = kontinue.Execute[DeployResult](ktx, "deploy-service", &DeployArgs{
        Service: args.Service,
        Version: args.Version,
        Cluster: "production",
    }, nil)
    if err != nil {
        return nil, err
    }

    return &ReleaseResult{Status: "completed"}, nil
}

The parent execution waits for each child regardless of which worker group handles it.

Function Ownership

Each function can only belong to one worker group at a time. If you try to register a function that’s already owned by another worker group, you’ll get an error:

function deploy-service is owned by worker group deployments (current worker group: releases).
Set TakeOwnershipOfFunctions=true to override

To migrate a function to a different worker group:

w, _ := worker.New(worker.Options{
    Namespace:                "infra",
    Group:                    "releases",
    TakeOwnershipOfFunctions: true,  // Take over functions from other groups
})

Use this option carefully to avoid conflicts between workers.

Function Pruning

By default, when a worker starts, it removes Functions that were previously registered by its worker group but are no longer in the code. This keeps the Function list clean.

To disable pruning (useful during rolling deployments):

w, _ := worker.New(worker.Options{
    Namespace:              "infra",
    Group:                  "deployments",
    DisableFunctionPruning: true,
})

Querying by Worker Group

Filter executions and functions by worker group using labels:

# List functions in a specific worker group
kubectl get functions -l kontinue.cloud/worker-group=deployments

# List executions in a specific worker group
kubectl get executions -l kontinue.cloud/worker-group=deployments

Via the client library:

functions, err := cli.Functions(ctx, &client.ListFunctionsOptions{
    WorkerGroup: "deployments",
})

executions, err := cli.List(ctx, &client.ListOptions{
    WorkerGroup: "deployments",
})

Best Practices

  1. Use descriptive group names: Choose names that reflect the domain or concern (deployments, provisioning, testing)

  2. Keep groups stable: Avoid frequently changing worker group names as this affects function ownership

  3. Document group boundaries: Make it clear which functions belong to which group

  4. Consider scaling independently: Each worker group can have its own deployment with different replica counts and resource limits