For the complete documentation index, see llms.txt.
Skip to main content
Version: 8.10 (unreleased)

Job workers

Technical Preview

The Go SDK is a technical preview. Its API surface may still evolve and changes may not follow semantic versioning. Pin an exact version if you need stability.

Register a REST activate-jobs worker with NewJobWorker. The handler's return value decides the job outcome:

// One JobHandler contract for both workers: returning variables completes the
// job; returning a *camunda.BpmnError throws a BPMN error; returning any other
// error fails the job (decrementing its retries).
worker := client.NewJobWorker("greet",
func(ctx context.Context, job *camunda.Job) (map[string]any, error) {
var in struct {
Name string `json:"name"`
}
if err := job.Variables(&in); err != nil {
return nil, err
}
return map[string]any{"greeting": "Hello, " + in.Name + "!"}, nil
},
camunda.WithMaxConcurrentJobs(10),
camunda.WithPollInterval(500*time.Millisecond),
)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// Run blocks until ctx is canceled, draining in-flight jobs on shutdown.
if err := worker.Run(ctx); err != nil {
fmt.Println("worker stopped:", err)
}

For high-throughput, low-latency work, use the gRPC streaming worker (NewStreamJobWorker) — a capability unique to this SDK among the Camunda Orchestration Cluster SDKs:

// The gRPC streaming worker activates jobs over a StreamActivatedJobs stream
// and acknowledges them over gRPC. A low-frequency REST sidecar poll backs it
// up (a safety net for jobs re-queued after a timeout or brief reconnect).
worker := client.NewStreamJobWorker("greet",
func(ctx context.Context, job *camunda.Job) (map[string]any, error) {
return map[string]any{"greeting": "Hello!"}, nil
},
camunda.WithStreamPollInterval(30*time.Second), // -1 disables the sidecar poll
)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

if err := worker.Run(ctx); err != nil {
fmt.Println("stream worker stopped:", err)
}

Pass camunda.WithStreamJobLease(true) to activate jobs with a lease. Each job then carries a lease token that the worker sends back when it completes, fails, or throws — so if the job timed out and another worker picked it up, the stale acknowledgement is rejected instead of racing the newer activation. It covers both the gRPC stream and the REST sidecar poll. The REST worker takes the same option as camunda.WithJobLease(true). Leases are off by default (matching the engine) and need an engine that supports them; older gateways ignore the flag and keep handing out unleased jobs.