Install
Works with Drupal: ^11.3 || ^12Using Composer to manage Drupal site dependencies
Alternative installation files
Release notes
WARNING: THERE IS NO MIGRATION PATH. YOU MUST REINSTALL FROM SCRATCH.
Do not update an existing site to this release. Orchestra ships no update hooks, and none is coming until the first beta release. A site on an earlier alpha holds a database and a module list this code does not match.
Uninstall the Orchestra modules, drop what they leave behind, and install 1.0.0-alpha22 fresh. Every instance, token, task, incident, variable, attachment and delegation from an earlier alpha is lost, and that is expected.
Between alpha21 and alpha22 in particular: tokens have four new fields (lineage, fork_lineage, branch_lineage, branch_match); the timeout join is gone; the quorum join and the collect setting of every merging join store different settings; the orchestra.notification_audience service is now orchestra.audience_resolver; and the optional views orchestra_instance and orchestra_tokens changed. No permission or path changed.
New
- A split can create one branch per item of a list known only at run time. The first such split is
per_member: each member of the step's audience gets a task of their own, in a branch of their own, so a quorum join can decide on their answers, as soon as enough of them have validated or too few still can. Contributed splits list their own items throughItemSplitInterface. Orchestra Examples ships a member validation workflow showing it. #3630353: Add splits creating one branch per item, starting with a per_member split - Every synchronizing join can have a timeout of its own, with what tasks already had: a duration, a date or a duration read from a variable, its anchors, the cron sweep, the "Fire timer now" action, and a timeout outcome to route on. On timeout, the join fires with the branches that arrived, or stops on an incident. The fire writes how many branches arrived and how many it waited for into variables of your choosing. This replaces the timeout join (see Removed). #3630897: Give joins a timeout of their own, and remove the timeout join
- A threshold or quorum join can leave the remaining branches running when it fires ("Ignore"), instead of canceling them or the whole split. #3629777: Add an "Ignore" mode to the threshold, quorum and timeout joins, leaving the remaining branches running
- A join can keep the token-scoped variables set in its branches, from the first or the last arrival, so a later step reads the decision or the comment of a branch. #3629938: Let a synchronizing join keep the branches' token-scoped variables, from the first or the last arrival
- A join can collect several branch variables, each into its own variable, as a list, a list without repeats, a count, a sum, an average, a minimum or a maximum, for example
amount|total_amount|sum. A quorum join counts a condition tested on each branch, as a number, a percentage or a majority, and can read its quorum from a variable. #3629948: Let a join collect several branch variables into lists, and let a quorum count a condition, as a number, a percentage or a majority #3630241: Let a join's collect line write the sum, average, count, minimum or maximum of the branches' values, instead of only their list - Node values: a list of named texts on a node, read as
[orchestra:node-value:NAME]and in Easy Email layouts, so one mail template serves every notification with the wording of each step. #3629515: Add node values, read as [orchestra:node-value:NAME] and in Easy Email layouts, so one template serves every notification - The people told about a task are notified when it is canceled, with a new
task_cancelednotification type. #3629770: Notify the people told about a task when the task is canceled
Changed
- Joins count branches, not incoming flows. A wait_all join waits for every path the split drew, and joins count every branch at every level of nested splits. A split drawn as separate flows behaves as before. #3630352: Count branches, not incoming flows, at joins
- A matching join waits for the branches still on their way, instead of evaluating the conditions on its incoming flows again. Those conditions no longer need repeating on the join's incoming flows. #3629950: Let a matching join wait for the branches still on their way, instead of re-evaluating the conditions on its incoming flows
- A join that can no longer fire raises an incident, instead of quietly lowering a threshold or quorum count to the branches that started, or only logging a stall. A count higher than the join's incoming branches is refused when the workflow is saved. #3629951: Raise an incident when a join can no longer fire, instead of lowering a threshold's count or only logging a stall
- The instance page shows a join's continuation as "Join fired", instead of a second arrival down the flow that fired it, and lists each variable's value and scope beside its name. #3631032: Show a join's continuation as the join firing, and each variable's value beside its name
- Token states are shown by their translatable label in the instance trace and the token views, and the styled tag option colors them by state. #3630159: Show token states by their translatable label in the instance trace and the token views, instead of the raw machine name #3630244: Color token state tags by state, as task and instance state tags are, and let the state label field base offer the tag option
- An Orchestra administrator can open a task somebody else holds, and the instance trace offers Reassign and Return to pool. #3629260: Let an Orchestra administrator open a task somebody else holds, and offer Reassign and Return to pool on the instance trace page
- In the modeler, each join's and human task's own settings come before the shared ones. #3629738: Show each join's and human task's own settings before the shared ones in the modeler
- The audience and recipient lists name their entries "Audience 1", "Recipient 1" instead of "Row 1". #3629215: Name the entries of the audience and recipient lists instead of "Row"
- The initiator is labeled "Initiator", not "Beneficiary", in the inbox views and on the instance page. #3629180: Label the initiator "Initiator" in the inbox views and on the instance page, not "Beneficiary"
- The French translation says « jonction » and « embranchement » for join and split. #3630934: Use "jonction" and "embranchement" for join and split in the French translation
Fixes worth naming
- A disabled remote could still write into this site's instances. Its signed notices were accepted, and set the variables and status they carried on the parent instances waiting on its children. They are now refused with a 403, like an unverified notice. #3631028: Refuse the notices of a disabled remote
- A step finishing after its branch was canceled could revive the branch. A token's state is now saved only if it is still valid. #3629851: Save a token's state only if it is still valid, so a step finishing after a cancellation cannot revive its branch
- A threshold or quorum join could leave a branch running after it fired, when the condition on that branch's incoming flow read a variable set after the split. #3629743: Cancel the branches still running when a threshold, quorum or timeout join fires, whatever conditions its incoming flows carry
- Retrying a join step that halted after it fired left its token waiting at the join forever. #3629866: Retrying a join step that halted after it fired leaves its token waiting at the join forever
- A join fired by a single branch lost what that branch set before the split. It now goes on with that branch's token. #3629949: Let a join fired by a single branch go on with that branch's token, so nothing it set before the split is lost
- Saving a canvas modeler merged a step's assignment rows for one audience into the first, with that row's notify settings, so a user the author chose not to email was emailed. #3630243: Keep a step's assignment rows and their notify settings when a canvas modeler saves it, instead of folding one audience's rows into the first
- Line breaks in node and flow labels are kept when saving in the Complete modeler, shown as a space on the instance trace page's Signal links, and valid config; BPMN.io no longer breaks words in labels drawn outside shapes. #3629202: Keep line breaks in node and flow labels when saving in the Complete modeler #3629259: Show a line break in a flow label as a space on the instance trace page's Signal links #3630976: Type node and flow labels as text, so a label with line breaks is valid config #3629196: Lay out the text of BPMN.io labels outside shapes in the width bpmn-js measured it in, so words are not broken
Performance
- Each token stores its ancestry as a path, so canceling a branch or finding the split a join closes reads it in one query instead of walking the tree; a join goes on with a new token, so a token's lineage never changes. #3629852: Store each token's ancestry as a path, and go on with a new token when a join fires, so a token's lineage never changes
- An arrival at a join reads the waiting tokens as rows, and loads entities only when the join fires. #3630351: Read the tokens at a join as rows, and load them only when it fires
Removed
- The
timeoutjoin. Use await_alljoin with a join timeout firing the join. #3630897: Give joins a timeout of their own, and remove the timeout join
For developers
- The engine, the editors and the submodules ask plugins what they do through capability interfaces, instead of naming specific plugins, so a contributed join, split or task takes part. #3630153: Ask plugins what they do, instead of naming specific plugins in the engine, the editors and the submodules
- Route callbacks and accessors are named with verbs, for example
InstanceTenantAccessCheck::checkInstanceAccess()andOrchestraUiController::buildInstancePage(). #3630245: Name the access checks, page callbacks and accessors with verbs, check notification types with MachineName, and correct the interaction docs on signal links - Incident resolution, the executor's token locks, a token's committed state, the completion scope and the routing plugin IDs are each read through one helper; pending actions are grouped by handler without
spl_object_id();armJoinTimeouts()takes no lock. #3630900: Resolve incidents, hold the executor's token locks and read a token's committed state through one helper each #3631029: Read the completion scope and the routing plugin IDs in one place each #3630602: Group pending actions by handler without spl_object_id() #3629917: Remove the join lock armJoinTimeouts() takes, which no advance shares, and rely on its guarded UPDATE
Housekeeping
- The codebase metrics page is refreshed: 1,514 files and 149,734 lines of code.
AI-Generated: Yes (Claude Code was used to help draft these release notes. I reviewed them.)