Implementing the BPMN Service Task Worker Pattern in Go
When you model a BPMN 2.0 process that calls an external service — sending an email, charging a credit card, calling a third-party API — you reach for a Service Task. The execution engine needs something to actually run that task, and that something is a job worker. Getting the worker pattern right in Go (Golang) means your workflow engine stays responsive, your jobs are idempotent, and errors feed back into the process where boundary events can handle them gracefully.
This tutorial walks through the complete BPMN service task worker pattern in Go using Priostack's REST API. By the end you will have a production-ready worker that polls for jobs, handles variables, retries on failure, and throws BPMN errors when the business logic cannot continue.
What is a Service Task Worker?
In BPMN 2.0, a Service Task represents work performed by an automated system rather than a human. When the workflow engine reaches a service task, it creates a job and waits. A worker is a separate process that:
- Polls the engine for available jobs of a specific type (e.g.,
send-email). - Locks the job to prevent concurrent processing.
- Executes the business logic (call the email API).
- Reports success (complete) or failure (fail / throw error) back to the engine.
This asynchronous, polling-based architecture means your workers can be deployed independently, scaled horizontally, and replaced without redeploying the workflow engine. It is the same model used by Zeebe (Camunda 8) and Activiti — Priostack implements the same protocol over REST, making Go workers trivial to write.
Setting Up the Priostack Worker SDK
Priostack exposes a REST job API. You do not need a gRPC dependency or a heavy SDK. A standard
net/http client is sufficient. First, sign up at priostack.com/quickstart
and get your API key.
Create a new Go module for your worker:
Define a minimal client struct that wraps the Priostack base URL and API key:
Now implement the ActivateJobs call. This is a long-poll: the engine holds the request open
for up to requestTimeout milliseconds, returning jobs as soon as one is available.
Handling Variables and Output Mapping
Service tasks exchange data with the process via variables. Input variables are available on
job.Variables; output variables are passed when completing the job.
To read input variables safely, use type assertions with defaults:
Error Handling and Retry Logic
Workers distinguish between two types of failure:
- Retryable failure — transient error (network timeout, rate limit). Call
FailJobwith retries decremented. When retries reach zero the engine creates an incident. - BPMN error — a domain-level error that should be caught by a boundary event
on the service task (e.g.,
EMAIL_BOUNCE). CallThrowError.
Implement exponential back-off when ActivateJobs returns an empty list (engine is idle) or
a server error, to avoid hammering the API:
Complete Example: Email Notification Service Task
Here is a full worker that handles an email-notification service task. It reads recipient,
subject, and body from process variables, calls a hypothetical email API, and completes the job with
a messageSid output variable.
Set the environment variables and run:
Conclusion
The BPMN service task worker pattern in Go is straightforward: poll, lock, execute, complete. The key design decisions are:
- Use long-polling to keep the connection efficient.
- Run each job in its own goroutine for concurrency.
- Distinguish retryable errors from BPMN errors — let the process model handle domain failures.
- Use exponential back-off when the queue is empty or the engine is unavailable.
Priostack's API keeps things simple — no gRPC, no heavy client library, just HTTP. You can have your first worker running in minutes.
Ready to run your first BPMN service task?
Get a free API key, deploy your BPMN, and have a worker polling in under 5 minutes.
Quickstart guide API docsFrequently Asked Questions
What is a BPMN service task worker?
A BPMN service task worker is a long-running process that polls a workflow engine for pending jobs of a specific type, executes the business logic, and reports the result back to the engine. The worker pattern decouples your business logic from the workflow orchestration layer.
How do I implement a BPMN worker in Go?
With Priostack, poll for activated jobs via POST /api/v1/jobs/activate, process each
job in a goroutine, and complete them via POST /api/v1/jobs/{key}/complete. See the
full code example above.
What is the difference between a job worker and a service task?
A service task is the BPMN modelling concept — a task in your process diagram that calls an external service. A job worker is the runtime implementation — the Go process that subscribes to that service task type and executes it.
How does error handling work in BPMN service task workers?
Workers can report job failure via POST /api/v1/jobs/{key}/fail with a decremented
retries count. When retries reach zero the engine creates an incident. For domain errors, use
POST /api/v1/jobs/{key}/error to throw a BPMN error caught by boundary events.
Can I use Priostack as a Camunda/Zeebe worker replacement?
Yes. Priostack's job worker API is protocol-compatible with the Zeebe job worker model. Point your existing worker endpoint at Priostack and it works without code changes. See also: migrating from Camunda.
Related: Enterprise integration patterns without a message broker · Two-layer BPMN architecture · Docs: Job Workers