Install
$ agentstack add skill-camunda-skills-camunda-job-workers ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Camunda Job Workers
Implement job workers for Camunda 8.8+ in Java, Camunda Spring Boot, or TypeScript. A job worker is the handler that the Zeebe engine hands an activated job to — it runs business logic, then signals success, failure, or a BPMN error back to the engine.
Prerequisites
- Camunda 8.8+ cluster reachable from the worker process (local c8run, SaaS, or Self-Managed — see camunda-c8ctl)
- A BPMN process with at least one element that has `` matching the worker's job type (see camunda-bpmn)
- Toolchain for the chosen SDK — OpenJDK 17+ and Maven/Gradle for Java and Spring; Node.js 18+ for TypeScript. SDK-specific version constraints (e.g. Spring Boot 4 vs 3, browser support) are in each SDK's reference. See camunda-development for installing these locally.
Cross-References
- camunda-development: Use first to decide whether a worker is the right shape at all (vs. an OOTB connector, a JSON-only protocol-connector template, or a custom Java connector via the SDK)
- camunda-connectors-development: Use when the integration is closer to a reusable Java connector than to application-bound worker code, or when the integration needs inbound triggers (workers are outbound-only)
- camunda-bpmn: Use for the service-task / receive-task element and its
zeebe:taskDefinition, plus the boundary events that catch the worker's BPMN errors - camunda-feel: Use for FEEL in
zeebe:taskHeadersand for the gateway conditions that consume the worker's output variables - camunda-process-mgmt: Use for deploying the process, starting instances against the running worker, and inspecting jobs / incidents from the cluster side
- camunda-process-test: Use for end-to-end tests that drive worker handlers through an embedded Zeebe engine
When to write a job worker
Walk camunda-development first. The short version of the matrix as it applies here:
- Non-Java stack (TypeScript, plus any other official SDK in scope for a future release): worker is the path. Connectors are Java-only.
- Java stack, logic already lives in the app: worker keeps the logic in the codebase that owns it.
- Java stack, reusable across processes / projects / clusters: prefer a custom connector via camunda-connectors-development.
- Inbound triggers (an external system pushes events into a process): always a connector — workers exclusively pull activated jobs from the engine.
Job lifecycle
A worker's contract with the engine has four states:
- Activate — the worker requests jobs of a given
type(polling) or receives them on a streamed connection. Each activation has a timeout (the lease the engine grants before it will hand the same job to another worker if the first doesn't respond) and a fetch-variables list (which process variables the engine ships with the job). - Handle — the worker runs the handler code with the activated
job(variables, headers, retries remaining, key). - Complete — the worker calls
complete(or returns a value withautoComplete=true). The engine merges the worker's output variables into the process scope and advances the token. Variables propagate from the job's scope up to the enclosing scopes per BPMN rules. - Fail — the worker either calls
failexplicitly with a remaining-retries count and an optional back-off, or throws. If retries reach zero, the engine raises an incident and the instance pauses until an operator resolves it (see camunda-process-mgmt).
Activation timeout vs. retries are independent. A timeout means the engine reassigns the job without decrementing retries; a fail with retries left means the same job will be redelivered after the back-off. Long-running handlers should extend the timeout via UpdateJobTimeout rather than racing the lease.
Idempotency — handle every job at least twice
The engine's at-least-once delivery guarantees that a handler may run more than once for the same job.key. Activation timeouts, network blips, and retries after a failed complete call all cause redelivery. Handlers must be idempotent.
Two patterns work well:
- Idempotency token in your downstream system. Use
job.key(or a deterministic value derived from process variables) as a request id / Idempotency-Key header / database unique constraint. A retry of the same job hits the same key and is suppressed. - Check-before-write. Query the downstream system for the side effect's marker before applying it. Cheap when the system supports it; not always available.
Storing local "has this job ran?" state in the worker process is not idempotency — the process can crash, scale out, or be replaced.
Failure modes — three distinct paths
The choice depends on whether the failure is a transient infrastructure problem, a modelled business outcome, or an unexpected programming error:
- Transient failure → fail with retries and back-off. Network timeout, downstream 5xx, broker unreachable. The handler decrements retries and asks the engine to redeliver after a back-off. Reaching zero retries raises an incident.
- Business outcome → BPMN error. The handler succeeded in identifying a failure modelled in the BPMN — payment declined, inventory empty, license rejected. Throw a BPMN error with a code that an error boundary event (or error end event in a subprocess) catches. The job is not retried — the engine takes the error path.
- Programming error → unhandled exception. A NullPointerException, an unhandled promise rejection, a type error. SDKs fall back to fail-with-zero-back-off — the engine redelivers immediately, burns retries, and raises an incident. Never use unhandled exceptions as a control-flow signal: the zero back-off thrashes the cluster, and a future SDK change could redefine the default.
The SDK-specific call signatures (CamundaError.jobError / CamundaError.bpmnError for Spring, newFailCommand / newThrowErrorCommand for the Java client, job.fail / job.error for TypeScript) are in the per-SDK references.
Auto-complete vs. explicit complete
The Camunda Spring Boot Starter's @JobWorker auto-completes by default: the handler's return value is serialised as the job's output variables. Set autoComplete = false when the handler needs to call complete itself (conditional variables, asynchronous response, ownership transfer).
The Java client and TypeScript SDK do not auto-complete — the handler must call complete, fail, or error on every code path. Missing a terminal call leaks the job's lease until activation timeout.
Pick an SDK
| SDK | When to pick | |---|---| | Camunda Spring Boot Starter — camunda-spring-boot-starter ([ref](references/worker-sdk-spring.md)) | New Java applications. Annotation-driven (@JobWorker), auto-complete, config via application.yaml. The default Java path. | | Java client — camunda-client-java ([ref](references/worker-sdk-java.md)) | Standalone JVM applications, non-Spring frameworks, libraries embedding Zeebe access. Lower-level builder API. Replaces the deprecated Zeebe Java Client (removed in 8.10). | | TypeScript — @camunda8/orchestration-cluster-api ([ref](references/worker-sdk-typescript.md)) | Node.js workers, browser-hosted clients, 8.9+ projects. Fall back to @camunda8/sdk (Node-only) only when gRPC streaming, sub-8.8 targets, or migration friction explicitly require it. |
Spring Boot 4 vs. 3 — high-stakes routing
> The default Camunda Spring Boot Starter (camunda-spring-boot-starter) is bundled with and requires Spring Boot 4.0.x.
Applications still on Spring Boot 3.5.x use camunda-spring-boot-3-starter as a migration bridge — Spring's OSS support for the 3.5.x line ends June 2026. Don't mix the two starters on one classpath: the SB4 starter won't start on a Spring Boot 3 app, and the SB3 starter pulls conflicting transitive deps into a Spring Boot 4 app.
All starter modules require OpenJDK 17+.
Common pitfalls
- Forgetting to complete / fail / error a job (Java client, TypeScript). The lease times out and the engine redelivers. Handlers must hit exactly one terminal call on every code path. Spring's
autoComplete = truecovers happy-path returns; failure paths still need an explicit signal. - Treating unhandled exceptions as BPMN errors. An unhandled throw is a programming error, not a modelled outcome. SDKs fail the job with
retries - 1andretryBackoff = 0— the engine redelivers immediately, burns retries, and raises an incident. - Storing "already processed" state in the worker process. Crashes and scale-out erase it. Idempotency belongs in the downstream system or in process variables that survive redelivery.
- Polling and request-timeout misalignment. The activation request timeout must be shorter than the gateway / load-balancer cutoff, otherwise the worker tears the connection down and reconnects in a loop. SDK defaults are sensible — change them deliberately.
References
For SDK-specific detail, read from references/:
- [worker-sdk-java.md](references/worker-sdk-java.md) —
camunda-client-java: client bootstrap,JobWorkerBuilder, command builders, streaming, multi-tenancy, OAuth config - [worker-sdk-spring.md](references/worker-sdk-spring.md) — Camunda Spring Boot Starter:
@JobWorkerparameter reference,@Variable/@VariablesAsType,CamundaError, configuration property tree, Spring Boot 4 vs 3 starter selection - [worker-sdk-typescript.md](references/worker-sdk-typescript.md) —
@camunda8/orchestration-cluster-api:createJobWorker/createThreadedJobWorker, job-handler return shapes, when to fall back to@camunda8/sdk
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: camunda
- Source: camunda/skills
- License: Apache-2.0
- Homepage: https://camunda.com
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.