gobpm

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 28, 2026 License: LGPL-3.0 Imports: 0 Imported by: 0

README

GoBPM — BPMN 2.0 Process Engine for Go

GitHub License GitHub Tag GitHub go.mod Go version codecov Go Report Card Go Reference

GoBPM is a native Go BPMN 2.0 engine. It is designed to embed directly into a Go application as a minimal, dependency-light library — and to scale up to a standalone process server through additive runtime components, without forcing library users to ship what they don't need.

Status: v0.1.1 — active development, not yet production-ready.

The vision, scope, and architecture are defined in SAD-001 and its ADRs; the delivery plan is the Development Roadmap.

Two journeys

  1. Embedded library. import github.com/dr-dobermann/gobpm, build an engine, register a process, run it. No external services required.
  2. Standalone runtime. A gobpm-server (planned, runtime/ module) exposes the engine over HTTP/gRPC with real persistence, identity, and observability — built on the library, never a fork of it.

The library carries no runtime baggage; the runtime never reimplements the engine.

Key characteristics

  • Library, not framework — embeds into your Go binary; no JVM, containers, or external services. Core depends only on the Go stdlib + github.com/google/uuid.
  • BPMN 2.0 Process Execution Conformance — the Common Executable Subclass plus the ComplexGateway extension. Authoritative scope: docs/bpmn-spec/conformance.md.
  • Predictable execution model — one event-loop goroutine per process instance owns state; each track (thread of execution) runs in its own goroutine, and a token is a projection of a track's position, not a stored object; context.Context is the cancellation contract. See ADR-001.
  • Interface-driven extensibility — persistence, expressions, messaging, observability, authorization, task distribution, and clock are all behind interfaces with in-core defaults. See ADR-002.
  • Observable by defaultLogger defaults to slog.Default(); you opt out of telemetry, you don't opt in. Tracer/metrics default to no-op (OpenTelemetry adapter ships separately).
  • Message handling & correlation — send/receive tasks and throw/catch message events over a pluggable broker; a message can instantiate a process (event-triggered instantiation) and correlate to the right instance by a key derived from the payload, and a follow-up message routes back to the specific running instance whose conversation it belongs to — across one or more keys (conversation-token threading). See ADR-014 / ADR-015 / ADR-016.
  • Programmatic model construction — processes are built in Go. XML parsing is intentionally decoupled from the model layer.

Architecture

Process model ──> Snapshot ──> Engine (Thresher) ──> Instance (orchestrator)
   pkg/model        immutable      pkg/thresher          1 goroutine / instance
                    definition                            ├── Tokens (1 goroutine each)
                                                          ├── EventHub + waiters
                                                          └── Scope (hierarchical data)

Dependencies flow downward only; lower layers know nothing of higher ones.

Core packages
Package Description
pkg/thresher/ Engine façade — process registry and instance lifecycle
pkg/model/ BPMN element types (activities, events, gateways, flow, data, …)
pkg/errs/, pkg/set/ Structured errors; utility data structures
internal/instance/ Instance / track / token execution (+ snapshot/)
internal/eventproc/ EventHub + event waiters (timer, …)
internal/scope/ Hierarchical data scoping and variable shadowing

Quick start

go get github.com/dr-dobermann/gobpm
// Start -> ServiceTask -> End  (errors elided for brevity)
engine, _ := thresher.New("demo-engine")

proc, _ := process.New("demo-process")
start, _ := events.NewStartEvent("start")

// A ServiceTask runs your Go code: gooper.New builds the operation straight
// from a functor. The functor receives a read-only DataReader (process data
// and engine runtime variables) and its optional bound input message — nil
// here, since this operation declares no messages — and returns its result.
op, _ := gooper.New("hello",
    func(_ context.Context, _ service.DataReader, _ *data.ItemDefinition) (*data.ItemDefinition, error) {
        fmt.Println("  ▶ hello from inside the process")
        return nil, nil
    })
task, _ := activities.NewServiceTask("work", op, activities.WithoutParams())

end, _ := events.NewEndEvent("end")

_ = proc.Add(start)
_ = proc.Add(task)
_ = proc.Add(end)
_, _ = flow.Link(start, task)
_, _ = flow.Link(task, end)

_ = engine.RegisterProcess(proc)
_ = engine.Run(context.Background())

// StartProcess returns a read-only handle onto the running instance.
inst, _ := engine.StartProcess(proc.ID())

// Block until the instance finishes — the guaranteed completion signal.
state, _ := inst.WaitCompletion(context.Background())
fmt.Println("done:", state) // "Completed"

The gooper functor is how you embed arbitrary Go logic in a process — the same pattern scales from a Println to a real handler.

StartProcess hands back a read-only InstanceHandle — your window onto the running instance: State(), a live Tokens() snapshot, full History() (every track, including merged ones), read-only Data(), and WaitCompletion(ctx) to await the finish. To follow progress as it happens, subscribe an observer to the instance's lifecycle / token / node event stream:

// an Observer is any type with OnEvent(thresher.Event):
type logger struct{}

func (logger) OnEvent(ev thresher.Event) {
    fmt.Printf("  • %s %s %s\n", ev.Kind, ev.NodeName, ev.State)
}

sub := inst.Observe(logger{})
defer sub.Cancel() // deregister + drain; sub.Dropped() counts any overflow

Delivery is best-effort and lossy — a slow observer drops events rather than blocking the engine — so the completion signal from WaitCompletion is the one guaranteed, never-dropped event.

A complete, runnable version (with error handling and waiting for the task to run) lives in examples/basic-process/; see also examples/parallel-gateway/ (concurrent branches), examples/process-data/ (process data through the task), and the timer examples examples/simple-timer/ · examples/timer-event/.

For the routing gateways, see examples/gateway-routing/ (exclusive choice) · examples/inclusive-join/ (inclusive split + OR-join) · examples/complex-gateway/ (activation-threshold join), and the Event-Based gateway — examples/event-based-gateway/ (mid-flow deferred choice: the first of several events to fire wins, the rest are dropped) · examples/event-based-parallel-start/ (a process started by an event gateway — the first of two correlated messages creates the instance, the other re-arms to it, and it completes once both have arrived).

For message handling, see examples/message-send-receive/ (a SendTask publishes to the broker, a ReceiveTask waits and binds the payload) · examples/message-intermediate-events/ (throw/catch message events), and examples/inter-instance-correlation/ — a message instantiates a handler process and correlates by a key derived from the payload (one handler instance per distinct order) · examples/conversation-routing/ — a follow-up message routes back to the specific handler instance whose conversation it belongs to (keyed in-instance receivers; two conversations stay isolated).

For signal events (broadcast, no correlation), see examples/signal-broadcast/ — one throw reaches every waiting catcher in reach · and examples/signal-start/ — a broadcast signal instantiates processes whose start trigger is a signal (one broadcast → one instance per signal-start declaration).

For boundary events (interrupting an activity), see examples/boundary-events/ — an interrupting timer boundary as a timeout on a long-running task: the 2s boundary fires before the ~4s activity finishes, cancels it, and routes the token onto the boundary's exception flow.

For abnormal process termination, see examples/terminate-end-event/ — a Terminate End Event on one branch of a parallel process: the fraud-check branch reaches it and ends the whole instance, cancelling the in-flight payment mid-charge — the instance settles Terminated, not Completed.

Startup logging

thresher.New prints a startup report — an ASCII banner with the engine version and last commit, then one line per resolved extension — so the wiring is visible in the log at construction time. Both blocks are on by default; opt out per block when the noise isn't wanted:

// Fully silent startup:
eng, _ := thresher.New("worker-7",
    thresher.WithoutBanner(),        // drop the banner / version / commit
    thresher.WithoutStartupConfig(), // drop the per-extension config dump
)

Development

make tools     # one-time: install pinned dev tools (mockery, golangci-lint, govulncheck)
make ci        # full pre-push gate — mirrors GitHub CI exactly (tidy, lint, build, race tests, diff-coverage, vuln scan)

make test         # tests (generates mocks first)
make lint         # lint core module
make build        # build to ./bin/
make cover-check  # diff-coverage gate — changed lines must be >= COVER_MIN (run after `make test-all`)

make ci is the contract: green locally ⇒ green on CI. The Go toolchain is pinned (go.modgo1.25.11) so local and CI scan the identical standard library.

How we work
  • Specification-first — non-trivial changes start from a spec (SRD/FIX) referencing the governing ADR; the spec lands in the same change-set as its implementation.
  • master is protected — changes land only through a PR with a green check; no direct, force, or admin-bypass pushes.
  • Diff-coverage gate — CI fails when the lines a change adds or modifies are covered below COVER_MIN (95% now, rising toward 100%). It judges only changed lines, so the untouched-code backlog never blocks a PR. See SRD-002.
  • Design docs under docs/design/ (SAD-001, ADR-001…007) are the source of truth; see CONTRIBUTING.md.
Requirements

Documentation

License

LGPL-3.0 — see LICENSE.

Documentation

Overview

Package gobpm provides Business Processes Management system which allows to load, create, save and run BPMN v.2 compliant business processes.

Package consists two sub-pacages:

- model -- for loading, creating from scratch and saving business process models.

- thresher -- for running business processes, monitoring and controlling them.

Directories

Path Synopsis
adapters
dtable module
lua module
postgres module
sqlite module
Package main provides the command-line entry point for the GoBPM application.
Package main provides the command-line entry point for the GoBPM application.
internal
enginert
Package enginert provides a concrete renv.EngineRuntime assembled from the bundled default extensions.
Package enginert provides a concrete renv.EngineRuntime assembled from the bundled default extensions.
eventproc
Package eventproc provides event processing interfaces and implementations.
Package eventproc provides event processing interfaces and implementations.
eventproc/eventhub
Package eventhub provides event hub implementation for BPMN processes.
Package eventhub provides event hub implementation for BPMN processes.
eventproc/eventhub/waiters
Package waiters provides event waiter implementations for different event types.
Package waiters provides event waiter implementations for different event types.
instance
Package instance provides process instance management for BPMN execution.
Package instance provides process instance management for BPMN execution.
instance/snapshot
Package snapshot provides process instance snapshot functionality.
Package snapshot provides process instance snapshot functionality.
scope
Package scope provides data scoping and path management for BPMN process execution.
Package scope provides data scoping and path management for BPMN process execution.
pkg
auth
Package auth defines the AuthorizationProvider extension: the engine's authorization slot for sensitive operations.
Package auth defines the AuthorizationProvider extension: the engine's authorization slot for sensitive operations.
auth/allowall
Package allowall provides the engine's default AuthorizationProvider, which permits every request.
Package allowall provides the engine's default AuthorizationProvider, which permits every request.
clock
Package clock defines the Clock extension: the engine's source of time and timer scheduling, isolated behind an interface so timer-driven behavior is testable.
Package clock defines the Clock extension: the engine's source of time and timer scheduling, isolated behind an interface so timer-driven behavior is testable.
clock/clocktest
Package clocktest provides a controllable clock.Clock for time-dependent tests: Now is settable and After channels fire when the clock is advanced past their deadline.
Package clocktest provides a controllable clock.Clock for time-dependent tests: Now is settable and After channels fire when the clock is advanced past their deadline.
clock/syscl
Package syscl provides the system wall-clock implementation of clock.Clock, backed by time.Now and time.After.
Package syscl provides the system wall-clock implementation of clock.Clock, backed by time.Now and time.After.
errs
Package errs provides ApplicationError definition which is used as a standard error in the gobpm library.
Package errs provides ApplicationError definition which is used as a standard error in the gobpm library.
eventproc
Package eventproc holds the public event-production contracts a node implements/consumes: EventProcessor (a node that handles a fired event) and EventProducer (registers processors and propagates events).
Package eventproc holds the public event-production contracts a node implements/consumes: EventProcessor (a node that handles a fired event) and EventProducer (registers processors and propagates events).
exec
Package exec holds the public node-execution contracts (ADR-012 v.1): the node executor a model element implements, the synchronizing-join variant, and the data-binding consumer/producer + Frame surface.
Package exec holds the public node-execution contracts (ADR-012 v.1): the node executor a model element implements, the synchronizing-join variant, and the data-binding consumer/producer + Frame surface.
interactor
Package interactor provides interfaces for human interaction with BPMN processes.
Package interactor provides interfaces for human interaction with BPMN processes.
messaging
Package messaging defines the engine's message-delivery extensions.
Package messaging defines the engine's message-delivery extensions.
messaging/membroker
Package membroker provides the engine's default MessageBroker: an in-memory inbox + correlation router.
Package membroker provides the engine's default MessageBroker: an in-memory inbox + correlation router.
model/activities
Package activities provides BPMN activity implementations.
Package activities provides BPMN activity implementations.
model/artifacts
Package artifacts provides BPMN artifact implementations.
Package artifacts provides BPMN artifact implementations.
model/bpmncommon
Package bpmncommon provides common BPMN model elements and utilities.
Package bpmncommon provides common BPMN model elements and utilities.
model/data
Package data provides implementation of BPMN data elements including item definitions, data associations, properties, and formal expressions.
Package data provides implementation of BPMN data elements including item definitions, data associations, properties, and formal expressions.
model/data/goexpr
Package goexpr is a reference implementation of bpmncommon.FormalExpression interface to support go function as FormalExpression evaluation core.
Package goexpr is a reference implementation of bpmncommon.FormalExpression interface to support go function as FormalExpression evaluation core.
model/data/values
Package values provides typed variable and array implementations for BPMN data handling.
Package values provides typed variable and array implementations for BPMN data handling.
model/data_objects
Package dataobjects provides BPMN data object implementations.
Package dataobjects provides BPMN data object implementations.
model/events
Package events provides BPMN event implementations.
Package events provides BPMN event implementations.
model/expression
Package expression defines the ExpressionEngine extension: the engine-level indirection through which BPMN FormalExpressions are evaluated, so the evaluation strategy (Go-native, FEEL, JUEL, …) is swappable.
Package expression defines the ExpressionEngine extension: the engine-level indirection through which BPMN FormalExpressions are evaluated, so the evaluation strategy (Go-native, FEEL, JUEL, …) is swappable.
model/expression/goexpr
Package goexpr provides the Go-native default ExpressionEngine: it delegates to each FormalExpression's own Evaluate method (today's behavior).
Package goexpr provides the Go-native default ExpressionEngine: it delegates to each FormalExpression's own Evaluate method (today's behavior).
model/flow
Package flow provides BPMN flow elements and node definitions.
Package flow provides BPMN flow elements and node definitions.
model/foundation
Package foundation provides base BPMN element types and interfaces.
Package foundation provides base BPMN element types and interfaces.
model/gateways
Package gateways provides BPMN gateway implementations.
Package gateways provides BPMN gateway implementations.
model/hinteraction
Package hinteraction provides human interaction interfaces and implementations for BPMN.
Package hinteraction provides human interaction interfaces and implementations for BPMN.
model/hinteraction/consinp
Package consinp implements Rendered interface for user input from console.
Package consinp implements Rendered interface for user input from console.
model/msgflow
Package msgflow holds the message-flow choreography shared by the BPMN nodes that send and receive messages (ADR-014 v.1).
Package msgflow holds the message-flow choreography shared by the BPMN nodes that send and receive messages (ADR-014 v.1).
model/options
Package options provides configuration options for BPMN model elements.
Package options provides configuration options for BPMN model elements.
model/process
Package process provides implementation of BPMN Process elements and their execution.
Package process provides implementation of BPMN Process elements and their execution.
model/service
Package service provides BPMN service interfaces and implementations.
Package service provides BPMN service interfaces and implementations.
model/service/gooper
Package gooper provides the gobpm-native Go operation: a ServiceTask Operation implemented by an in-process Go functor that reads through a public data reader and, optionally, consumes/produces messages (ADR-011 v.5 §2.6).
Package gooper provides the gobpm-native Go operation: a ServiceTask Operation implemented by an in-process Go functor that reads through a public data reader and, optionally, consumes/produces messages (ADR-011 v.5 §2.6).
observability
Package observability defines gobpm's structured-logging and telemetry contracts: the Logger interface (satisfied directly by *slog.Logger) and the OpenTelemetry-shaped Tracer / MetricsRecorder interfaces.
Package observability defines gobpm's structured-logging and telemetry contracts: the Logger interface (satisfied directly by *slog.Logger) and the OpenTelemetry-shaped Tracer / MetricsRecorder interfaces.
observability/memmetrics
Package memmetrics provides the engine's default MetricsRecorder: an in-memory, queryable registry.
Package memmetrics provides the engine's default MetricsRecorder: an in-memory, queryable registry.
observability/memtrace
Package memtrace provides an opt-in observability.Tracer that retains the most recent completed spans in a bounded in-memory ring, queryable via Spans.
Package memtrace provides an opt-in observability.Tracer that retains the most recent completed spans in a bounded in-memory ring, queryable via Spans.
observability/noop
Package noop provides no-op observability implementations: a Tracer that creates inert spans (the engine's default tracer) and a MetricsRecorder that discards all measurements (the opt-out for metrics).
Package noop provides no-op observability implementations: a Tracer that creates inert spans (the engine's default tracer) and a MetricsRecorder that discards all measurements (the opt-out for metrics).
renv
Package renv defines the public runtime-environment contracts: EngineRuntime — the engine/server-level set of resolved extensions (the wired services) the Thresher owns and shares with the things that run BPMN — and the per-execution RuntimeEnvironment a node executes against (ADR-012 §2.3).
Package renv defines the public runtime-environment contracts: EngineRuntime — the engine/server-level set of resolved extensions (the wired services) the Thresher owns and shares with the things that run BPMN — and the per-execution RuntimeEnvironment a node executes against (ADR-012 §2.3).
repository
Package repository defines the Repository extension: the engine's persistence slot for Process Instance state.
Package repository defines the Repository extension: the engine's persistence slot for Process Instance state.
repository/memrepo
Package memrepo provides the engine's default Repository: a non-durable, in-memory store.
Package memrepo provides the engine's default Repository: a non-durable, in-memory store.
set
Package set provides generic set data structure for comparable types.
Package set provides generic set data structure for comparable types.
tasks
Package tasks defines the engine's task-routing extensions.
Package tasks defines the engine's task-routing extensions.
tasks/localdispatcher
Package localdispatcher provides the engine's default WorkerDispatcher: an in-process executor that runs each job's registered handler under a bounded worker pool (a counting semaphore), so it cannot spawn unbounded goroutines (the bounded-in-memory-defaults principle, ADR-002 §4.2).
Package localdispatcher provides the engine's default WorkerDispatcher: an in-process executor that runs each job's registered handler under a bounded worker pool (a counting semaphore), so it cannot spawn unbounded goroutines (the bounded-in-memory-defaults principle, ADR-002 §4.2).
thresher
Package thresher provides the main BPMN process execution engine.
Package thresher provides the main BPMN process execution engine.
runtime module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL