2026-11 / 07
Camunda research — a role that closes itself
OutcomeDesigned and ran a small Camunda 8 experiment: a role opened by a message, three parallel lanes whose work arrives as real child process instances, and a role that ends after its deadline once no child is still active.
Overview
The first experiment in a small collection about process design and runtime behaviour in Camunda 8. A role opens on a message, runs for a window, and drains: work that arrives during the window becomes child instances whose parent and root are the role, so the number of root instances stays small. A tiny operator page opens, feeds and cancels roles and edits a monthly or interval schedule.
Design requirement
A monthly window had to accept arbitrary work and then end by itself, without a polling loop and without every unit of work becoming another root process instance.
System
Problem
A window such as “this month” has to stay open for arbitrary work and then end by itself, but without a polling loop, and without every unit of work becoming another root instance that clutters the engine.
Initial assumption
Initial hypothesis
Starting each unit of work by message, or running it as an inline task inside the role, would be enough.
One message, role.open, starts the role. A parallel fork opens three lane scopes; each waits at an event-based gateway where an absolute deadline timer races a close message, and each owns a non-interrupting event sub-process whose call activity starts a real child instance. The lane stays alive until its active children finish, so the role ends at its deadline plus drain, with no start timer and no polling variable.
Constraint found
role.open # message, correlation key roleKey
work.a|b|c # non-interrupting event sub-process -> call lab-child-a|b|c
role.close # races the absolute deadline timerMessage-started work made every unit its own root instance, and inline tasks proved no parent relationship at all. Only a call activity inside a non-interrupting event sub-process gave real child instances whose parent and root are the role.
Rejected fix
The first design ran work as inline service tasks; a 13-assertion result from it was recorded and then discarded, because it measured scopes rather than child instances. The second started children by message and produced N roots.
Design decision
Model the role as a message-started process with three lane scopes and call-activity children, and let the lane stay alive until its active children finish.
Result
The design runs: roles open from a schedule or by hand, children run in the lanes, and the page shows each role with its running and completed children. Two earlier designs were wrong and are marked as such in the notes: work as an inline task proved no parent relationship, and work started by message made every unit a root instance. The full proof run (deadline race, three-message close, drain and cancellation cascade) is not finished, so the claims stay at “designed and exercised”.
Current boundary
Boundary: The full proof run (deadline race, three-message close correlation, drain and cancellation cascade) is not finished; the scheduler lives in the lab process and is not a distributed scheduler.
Next step: Run the proof end to end against the engine and record the totals before any claim is promoted.