fix(tasks): keep parallel task responses apart with variableKey and a slot-aware merge - #1072
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Parallel entries were merged by ToVariableName(task.key); two runs of the same task (e.g. two SubProcess starts) carried different payloads and the merge threw 'Parallel tasks produced conflicting output'. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…duplicate-slot warning ExternalHttpTaskExecutor wrote its response without the context's ResponseVariableKey, so a variableKey was ignored for that task type. The duplicate warning now names every distinct task key in the shared slot, and its docs match the variableKey behaviour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…notes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A parallel group re-writing a slot an earlier order left behind was compared against the inherited value and threw 'Parallel tasks produced conflicting output'. Only two branches of one round writing one slot differently is a conflict now; a single writer overwrites. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ge is slot-aware Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The InstanceQueryAppService constructor gained an ICurrentUser parameter; this test did not, so the Application test project stopped compiling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Nothing flagged · reviewed Architecture Inside the changed components — 2 viewsComponent view — Definition & validation Validation rules for task variableKey slots across workflows and functions Component view — Parallel execution & branch merge Task coordination, per-slot response assignment, and two-pass parallel branch merging Data flow View
Tip Untick Architecture lens or Data flow lens under View to hide a diagram, or tick Expand every detail to open every section. The comment redraws in a few seconds 🪧 More tips
Thanks for using PR Lens! It's built by Coldtea, free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
|
Overall Grade |
Security Reliability Complexity Hygiene |
Code Review Summary
| Analyzer | Status | Updated (UTC) | Details |
|---|---|---|---|
| C# | Oct 5, 2026 6:57a.m. | Review ↗ |
Important
AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.
|




Summary
InvalidOperationException: Parallel tasks produced conflicting output for key 'subprocessTaskSendNotification'(ScriptContext.MergeDictionary). Entries at oneorderrun in parallel and are merged by response slotToVariableName(task.key); the same task listed twice at one order (e.g. two SubProcess starts) wrote one slot with different payloads (new instance id,ExecutionDurationMs), so the merge threw on practically every run.variableKey; the effective slot isvariableKey ?? ToVariableName(task.key), used verbatim.TaskCoordinatorthreads it into the existingTaskEngineExecutionOptions.ResponseVariableKey, which every executor now honors (ExternalHttp did not).variableKey(WorkflowValidator;FunctionComponentValidatorcompares effective slots across allonExecutionTasks). Definitions withoutvariableKeybehave exactly as before.ScriptContext.MergeParallelBranches): one round is merged by the slots each branch actually wrote (reference inequality against the parent — branches container-copy the dictionaries). A later order re-writing an earlier slot overwrites it, also when it runs as a parallel group (this used to throw too); only two branches of one round writing one slot differently is a conflict, detected before anything is applied.Changes
Definitions/Tasks/OnExecuteTask.cs:VariableKey, computedResponseVariableKey([JsonIgnore]),IsValidVariableKey.Definitions/Validators/WorkflowValidator.cs(ValidateTaskCollection),Definitions/Validators/FunctionComponentValidator.cs: slot and format rules.Tasks/Coordinator/TaskCoordinator.cs:ResolveGroupEngineOptionsthreadsVariableKey(caller/extension key still wins); duplicate-slot warning groups by slot; round merge call.Scripting/Models.cs:MergeParallelBranches(two-pass),MergeParallelBranchas a one-branch round;MergeDictionary/MergeMetadataremoved.Tasks/Executors/Http/ExternalHttpTaskExecutor.cs: passesResponseVariableKey.Functions/FunctionAppService.cs: single-task slot uses the effective key.Logging/WorkflowLogs.cs,docs/runtime/script-context-and-engine.md,docs/domain/fan-out-task.md,vnext-meta/features.json(taskVariableKey, since 0.0.99).OnExecuteTaskVariableKeyTests,WorkflowValidatorTests,FunctionComponentValidatorTests,TaskCoordinatorGroupEngineOptionsTests,TaskCoordinatorDuplicateTaskKeyTests,ExternalHttpTaskExecutorTests,ScriptContextCowBranchTests(the three pins of the old inherited-slot comparison are rewritten as two-branch conflicts; new: overwrite, untouched-by-reference, conflict atomicity, metadata).Test Plan
ScriptContext*,WorkflowValidatorTests,OnExecuteTaskVariableKeyTests— 232/236; the 4 reds are theDefaultAutoTransitiontests, also red on mastercddab84c.dotnet build vnext.sln0 errors.Integration test evidence
vnext-exampleTests/ParallelVariableKeyLab(--filter FullyQualifiedName~ParallelVariableKeyLab), flowspvk-parent(same SubProcess task twice at one order withvariableKey, plus a legacy-slot entry) andpvk-reuse(a parallel group re-writing an earlier order's slot), plus three publish-rejection probes.8046dbd6and, after merging master,8f11acfc, atVNEXT_BASE_URL=http://localhost:4201(run-docker.sh up core, local build).cddab84c: 0/5 —pvk-reuseFaulted withParallel tasks produced conflicting output for key 'pvkSpawnChild', publish probes answered 200.4f5c8cc95f9f65cb2de3fbdf4b067abc— order-2 spawns ran in parallel (51.7 / 46.8 ms, OK); 0 "conflicting output" logs after rebuild; Postgres: three distinct child ids in the parent's latest data row, childrenwaiting.FullyQualifiedName!~CrossDomainLab) on8046dbd6: 357 passed / 38 failed / 9 skipped (404). All 29 distinct failing tests also fail on mastercddab84c(RoleMatrixLab, HumanTaskChain — partner/credit not up, DataIntegrityLab, two role tests, TaskInvocationLab DaprService); no new red.TEST-SCENARIOS.mdrow added/updated: yes (parallel-variable-key-lab).Notes
variableKeyis now rejected at publish — that shape crashed at run time on most runs before (it could pass only when both payloads happened to be identical).variableKeyin function definitions; workflows already accept it). Scenario PR in burgan-tech/vnext-example follows.577110a7): master'sInstanceQueryAppServiceCorrelationTreeTestsmissed thecurrentUserconstructor argument and the Application test project did not compile.🤖 Generated with Claude Code