Description
ExecutorBinding.SupportsConcurrentSharedExecution contributes to whether a workflow can be used with InProcessExecution.Concurrent.
I found two binding paths where the underlying concurrency capability is not preserved:
BindAsExecutor(..., threadsafe: false) creates a FunctionExecutor that is not cross-run shareable, but the configured binding currently reports concurrent shared execution as supported.
SubworkflowBinding reports concurrent shared execution as supported even when its child workflow is not concurrent-capable.
As a result, workflows can be accepted by the concurrent execution path even though one of the shared execution paths does not support concurrent runs.
The subworkflow case is independently reproducible using a direct non-shareable executor, so it does not depend on the function-binding behavior.
Expected behavior:
threadsafe: false, including the default value, should make a shared function binding ineligible for concurrent workflow runs.
threadsafe: true should remain eligible.
- A subworkflow binding should reflect whether its child workflow supports concurrent runs.
- Invalid concurrent execution should be rejected at the appropriate workflow boundary.
Code Sample
Function binding
Func<int, int> handler = static value => value;
ExecutorBinding binding =
handler.BindAsExecutor("Function", threadsafe: false);
Workflow workflow =
new WorkflowBuilder(binding).Build();
await using StreamingRun run =
await InProcessExecution.Concurrent.OpenStreamingAsync(workflow);
// Actual: the concurrent run is accepted.
// Expected: InvalidOperationException.
Independent subworkflow case
static ValueTask HandleAsync(
int message,
IWorkflowContext context,
CancellationToken cancellationToken) => default;
FunctionExecutor<int> childExecutor =
new("Child", HandleAsync, declareCrossRunShareable: false);
Workflow child =
new WorkflowBuilder(childExecutor.BindExecutor()).Build();
ExecutorBinding childBinding =
child.BindAsExecutor("ChildWorkflow");
Workflow parent =
new WorkflowBuilder(childBinding).Build();
await using StreamingRun run =
await InProcessExecution.Concurrent.OpenStreamingAsync(parent);
// Actual: the parent passes the concurrent eligibility check.
// Expected: the parent is rejected because its child workflow is not
// concurrent-capable.
Error Messages / Stack Traces
No exception is produced at the affected eligibility boundary.
The expected behavior is the existing InvalidOperationException used when concurrent execution is requested for a workflow containing a binding that does not support concurrent shared execution.
Package Versions
Microsoft.Agents.AI.Workflows: 1.21.0
The same affected implementation is present in the dotnet-1.21.0 source tag. Runtime reproduction below was performed against current microsoft/agent-framework main; the release tag was inspected at source level only.
.NET Version
.NET SDK 10.0.401
Additional Context
The threadsafe parameter already describes whether a function handler may be used simultaneously by multiple runs. The function case appears to lose that capability when the FunctionExecutor is converted into a configured binding.
The subworkflow case appears to be the same capability-propagation issue at the workflow boundary: the child workflow can be non-concurrent while the binding presented to its parent reports concurrent support.
I have a small patch and deterministic regression coverage for both cases. If maintainers would prefer the subworkflow case to be handled separately, I am happy to split it into a follow-up.
I'm happy to work on the fix if this direction looks appropriate.
Description
ExecutorBinding.SupportsConcurrentSharedExecutioncontributes to whether a workflow can be used withInProcessExecution.Concurrent.I found two binding paths where the underlying concurrency capability is not preserved:
BindAsExecutor(..., threadsafe: false)creates aFunctionExecutorthat is not cross-run shareable, but the configured binding currently reports concurrent shared execution as supported.SubworkflowBindingreports concurrent shared execution as supported even when its child workflow is not concurrent-capable.As a result, workflows can be accepted by the concurrent execution path even though one of the shared execution paths does not support concurrent runs.
The subworkflow case is independently reproducible using a direct non-shareable executor, so it does not depend on the function-binding behavior.
Expected behavior:
threadsafe: false, including the default value, should make a shared function binding ineligible for concurrent workflow runs.threadsafe: trueshould remain eligible.Code Sample
Function binding
Independent subworkflow case
Error Messages / Stack Traces
No exception is produced at the affected eligibility boundary.
The expected behavior is the existing
InvalidOperationExceptionused when concurrent execution is requested for a workflow containing a binding that does not support concurrent shared execution.Package Versions
Microsoft.Agents.AI.Workflows: 1.21.0
The same affected implementation is present in the
dotnet-1.21.0source tag. Runtime reproduction below was performed against currentmicrosoft/agent-frameworkmain; the release tag was inspected at source level only..NET Version
.NET SDK 10.0.401
Additional Context
The
threadsafeparameter already describes whether a function handler may be used simultaneously by multiple runs. The function case appears to lose that capability when theFunctionExecutoris converted into a configured binding.The subworkflow case appears to be the same capability-propagation issue at the workflow boundary: the child workflow can be non-concurrent while the binding presented to its parent reports concurrent support.
I have a small patch and deterministic regression coverage for both cases. If maintainers would prefer the subworkflow case to be handled separately, I am happy to split it into a follow-up.
I'm happy to work on the fix if this direction looks appropriate.