Activity iteration¶
Any activity — a task, a sub-process, a call activity — can run more than once. gobpm models this with a loop characteristics marker attached to the activity: a Standard Loop repeats the inner activity while a condition holds, and a Multi-Instance runs it a fixed number of times over a cardinality or a collection. This page is the family reference — the marker interface, its two members, how you attach one, and the shape they share. Each member has its own page for the option catalog and runtime behavior.
The family¶
classDiagram
class LoopCharacteristics {
<<interface, sealed>>
}
class StandardLoopCharacteristics {
+LoopCondition() data.FormalExpression
+LoopMaximum() (int, bool)
+TestBefore() bool
}
class MultiInstanceLoopCharacteristics {
+IsSequential() bool
+LoopCardinality() data.FormalExpression
+CompletionCondition() data.FormalExpression
+Behavior() MultiInstanceBehavior
}
LoopCharacteristics <|.. StandardLoopCharacteristics
LoopCharacteristics <|.. MultiInstanceLoopCharacteristics
LoopCharacteristics is a sealed marker — its only method is unexported, so
just these two concrete kinds implement it, and the concrete kind selects the
execution mechanism (ADR-025 §2.1–§2.2). An activity carries at most one.
Members¶
| Kind | Type | Role | Page |
|---|---|---|---|
| Standard Loop | activities.StandardLoopCharacteristics |
sequential, condition-driven repetition (while / do-while) — BPMN §13.3.6 | Standard Loop |
| Multi-Instance | activities.MultiInstanceLoopCharacteristics |
fixed fan-out over a cardinality or a collection, one run per element — BPMN §13.3.7 | Multi-Instance |
Which to reach for: use Standard Loop when the repetition count is unknown up front and driven by a condition re-tested each pass; use Multi-Instance when the count is fixed at activation (an integer cardinality or a collection size) and each run handles one element.
Attaching a marker¶
Both kinds attach through the same activity option — WithLoop, which takes any
LoopCharacteristics:
func WithLoop(lc LoopCharacteristics) ActivityOption
Build the marker with its constructor, then pass it to any activity constructor. A Standard Loop:
loop, _ := activities.NewStandardLoop(cond,
activities.WithLoopMaximum(10))
task, _ := activities.NewServiceTask("retry", op,
activities.WithLoop(loop),
activities.WithoutParams())
A Multi-Instance attaches the same way — MultiInstanceLoopCharacteristics also
implements LoopCharacteristics:
mi, _ := activities.NewMultiInstance(
activities.WithInputCollection("orders", "order"),
activities.WithSequential())
task, _ := activities.NewServiceTask("process", op,
activities.WithLoop(mi),
activities.WithoutParams())
An activity holds a single marker — a later
WithLoopreplaces an earlier one (WithLoopdoc). The activity exposes the marker back viaLoopCharacteristics().A separate
WithMultyInstance() options.Optionexists as a legacy boolean flag on the task; the real Multi-Instance model is theWithLoop(NewMultiInstance(…))path above, not that flag.
Constructors¶
Each kind has its own constructor; both return an error — never panic — on an invalid combination:
func NewStandardLoop(
loopCondition data.FormalExpression,
opts ...StandardLoopOption,
) (*StandardLoopCharacteristics, error)
func NewMultiInstance(
opts ...MultiInstanceOption,
) (*MultiInstanceLoopCharacteristics, error)
| Constructor | Required | Errors on |
|---|---|---|
NewStandardLoop |
a non-nil boolean loopCondition |
a nil / non-boolean condition, or a bad option. |
NewMultiInstance |
exactly one cardinality source (WithCardinality XOR WithInputCollection) |
zero or both sources, a non-integer cardinality, or a non-boolean completion condition. |
Shared shape¶
Every marker embeds foundation.BaseElement, so it carries the common id /
documentation attributes of any BPMN element. Beyond that the two kinds share
nothing structurally — Standard Loop is a condition + optional maximum + a
pre/post-test flag; Multi-Instance is a cardinality/collection + per-iteration
data items + a completion condition + a completion behavior (whether and when
it throws an event as iterations finish). Those member-specific attributes and
their full option sets live on the two pages.
A taste of each option set (curated — the complete catalogs are on the member pages):
| Standard Loop option | Effect |
|---|---|
WithLoopMaximum(n int) |
cap the number of iterations. |
WithTestBefore() |
pre-test the condition (while); default is post-test (do-while). |
| Multi-Instance option | Effect |
|---|---|
WithCardinality(expr) |
fixed iteration count from an integer expression. |
WithInputCollection(ref, item) |
one iteration per element of the ref collection, bound as item. |
WithOutputCollection(ref, item) |
assemble each iteration's item back into the ref collection. |
WithSequential() |
run iterations one at a time; without it a Multi-Instance is parallel. |
WithCompletionCondition(expr) |
short-circuit the remaining iterations when the condition holds. |
WithBehavior(b) |
event-throwing behavior on iteration completion — BehaviorAll (default, none) / BehaviorNone / BehaviorOne / BehaviorComplex. |
What an iteration publishes¶
Both kinds publish runtime values a model can read — which iteration is running, how many there are, how many are done. The names, their addresses and their lifetimes are one table: Iteration runtime variables.
See also¶
- Members: Standard Loop · Multi-Instance
- Iteration runtime variables — what an iteration publishes
- Related guides: Activities taxonomy · Embedded Sub-Process
- Design: ADR-025 — Activity Iteration: Standard Loop & Multi-Instance
- Full API:
go doc github.com/dr-dobermann/gobpm/pkg/model/activities