Follow-up to #3608236: Extract a core execution service so the recovery and incident logic can move out and WorkflowEngine becomes a thin facade, second of two steps to take WorkflowExecutor below roughly 2000 lines; postponed on #3608366: Extract the loop-free leaf services from the WorkflowExecutor: token lineage, variables, deadline math, definition resolution, incident store, whose leaf services (VariableResolver, DeadlineCalculator) this builds on. The join machinery and the subprocess coordination cannot move mechanically: the loop calls them and they call the loop (tearDownCohort cancels stragglers, resumeParent resumes the parked parent), so a plain extraction would recreate the circular dependency #3608236: Extract a core execution service so the recovery and incident logic can move out and WorkflowEngine becomes a thin facade removed.

Split decision from action in both:

  • JoinCoordinator: evaluates an arrival and returns an outcome value object: fire or wait, the deadline to arm on a wait, the siblings to consume, the surplus deadlines to clear, the merge to apply, the new parent for the continuing token, and whether an early fire must tear the cohort down. The executor applies those side effects inside its existing per-(instance, node) lock and transaction, exactly where they happen today.
  • SubprocessCoordinator: computes the resume payload for a terminal child (the mapped result or the terminal status, its scope, and whether a retry re-launch should be armed instead) and owns armSubprocessRetry and relaunchDueSubprocess, which only make guarded database claims and read leaf services. The executor keeps the loop-bound tail: the atomic PARKED to ACTIVE claim and the resumeParked call.

Not a mechanical move: internal side-effect ordering changes, so the full join and subprocess matrix (JoinTest, JoinMergeTest, LoopJoinTest, ForkCohortTest, the three discriminator suites, JoinCancellationTest, JoinStallRecoveryTest, SignalIdempotencyTest, SubprocessTest) must stay green and the concurrency comments must move with the code.

Expected: roughly 440 lines net out of the executor, landing it just under 2000. One MR and one CI round.

Issue fork orchestra-3608367

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mably created an issue. See original summary.

mably’s picture

Status: Postponed » Active

mably’s picture

Status: Active » Needs review

Opened MR !280. The join machinery and the subprocess coordination now decide rather than act: a JoinCoordinator evaluates an arrival and returns a JoinOutcome value object (fire or wait, the wait deadline, the siblings to consume, the surplus deadlines to clear, the merge to write, the new parent, whether to tear the cohort down) that the executor applies inside the same per-(instance, node) lock and transaction as before; a SubprocessCoordinator computes the SubprocessResume payload for a terminal child and owns the guarded retry and re-launch claims, leaving the executor only the atomic PARKED to ACTIVE claim and the resume call. A shared FlowEvaluator hosts liveFlows and successors so the outgoing routing and the join arc matching keep one definition of "live". The dead-letter retry policy moved onto IncidentStore and the execution-mode read onto DefinitionResolver, so the executor no longer depends on the join, split, flow-condition or config-factory services.

WorkflowExecutor lands at 1936 lines (3662 originally, 2422 after #3608366: Extract the loop-free leaf services from the WorkflowExecutor: token lineage, variables, deadline math, definition resolution, incident store), with every public signature unchanged. The MR also enables _PHPUNIT_CONCURRENT in CI (the serial phpunit job had passed 17 minutes) and hardens a racy post-save assertion in OrchestraCmFeatureAuthoringTest that was diagnosed while verifying this change.

Verified locally: the dedicated join and subprocess matrix (30 tests), root kernel (183), unit plus all submodule kernel (328), all Functional in Docker (37), FunctionalJavascript (6), phpcs, cspell and phpstan parity.

  • mably committed a9d03f5c on 1.x
    task: #3608367 Rework the join and subprocess coordination into decide-...
mably’s picture

Status: Needs review » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.