.NET: Add support for Subworkflows and many threading fixes (#1066)

* feat: Add support for Workflow-as-Executor

* Fixes routing of 'object' compile-typed variables to properly take in type information
* Fixes a concurrency issue in StepTracer

* fix: Make Subworkflow ExternalRequests work properly

* fix: Threading and Concurrency fixes; prep for OffThread Mode

* refactor: Remove dead code around OffStreamRunEventStream

Currently not used, and will be replaced with a rewrite when brought back, so having it in the change is not valuable.

* ci: Work around issues with dotnet-format not properly analyzing the source

* fix: Fix the logic of AsyncCoordinator and AsyncBarrier

* Prevent individual wait cancellations from canceling the entire barrier
* Propagate information about whether the wait was completed or cancelled, and whether any waiters were present when released

* fix: Remove superfluous acces to .Keys in InProcStepTracer

* refactor: Clean up AsyncCoordinator's use of AsyncBarrier
This commit is contained in:
Jacob Alber
2025-10-03 17:26:30 +00:00
committed by GitHub
parent 880a99ca05
commit 32e7ff00b5
76 changed files with 2151 additions and 584 deletions
@@ -24,8 +24,6 @@ public abstract class Executor : IIdentified
/// </summary>
public string Id { get; }
private readonly ExecutorOptions _options;
private static readonly string s_namespace = typeof(Executor).Namespace!;
private static readonly ActivitySource s_activitySource = new(s_namespace);
@@ -37,9 +35,14 @@ public abstract class Executor : IIdentified
protected Executor(string id, ExecutorOptions? options = null)
{
this.Id = id;
this._options = options ?? ExecutorOptions.Default;
this.Options = options ?? ExecutorOptions.Default;
}
/// <summary>
/// Gets the configuration options for the executor.
/// </summary>
protected ExecutorOptions Options { get; }
/// <summary>
/// Override this method to register handlers for the executor.
/// </summary>
@@ -57,7 +60,7 @@ public abstract class Executor : IIdentified
/// <returns></returns>
protected virtual ISet<Type> ConfigureYieldTypes()
{
if (this._options.AutoYieldOutputHandlerResultObject)
if (this.Options.AutoYieldOutputHandlerResultObject)
{
return this.Router.DefaultOutputTypes;
}
@@ -132,11 +135,11 @@ public abstract class Executor : IIdentified
}
// If we had a real return type, raise it as a SendMessage; TODO: Should we have a way to disable this behaviour?
if (result.Result is not null && this._options.AutoSendMessageHandlerResultObject)
if (result.Result is not null && this.Options.AutoSendMessageHandlerResultObject)
{
await context.SendMessageAsync(result.Result).ConfigureAwait(false);
}
if (result.Result is not null && this._options.AutoYieldOutputHandlerResultObject)
if (result.Result is not null && this.Options.AutoYieldOutputHandlerResultObject)
{
await context.YieldOutputAsync(result.Result).ConfigureAwait(false);
}