From d7c6d07c5a4ee814ddfc6bfdf1c2efe7cb0ef2c0 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Mon, 10 Apr 2023 15:32:40 +0200 Subject: [PATCH] Update background activity invoker to only transport workflow-stored variables --- .../Elsa.Http/Activities/SendHttpRequest.cs | 2 +- src/modules/Elsa.Http/Features/HttpFeature.cs | 1 + .../Services/AmbientActivityContext.cs | 18 -------------- .../DefaultBackgroundActivityInvoker.cs | 24 +++++++++++++++++-- 4 files changed, 24 insertions(+), 21 deletions(-) delete mode 100644 src/modules/Elsa.Workflows.Runtime/Services/AmbientActivityContext.cs diff --git a/src/modules/Elsa.Http/Activities/SendHttpRequest.cs b/src/modules/Elsa.Http/Activities/SendHttpRequest.cs index ca13cb6a0..bfae9838d 100644 --- a/src/modules/Elsa.Http/Activities/SendHttpRequest.cs +++ b/src/modules/Elsa.Http/Activities/SendHttpRequest.cs @@ -112,7 +112,7 @@ public class HttpStatusCodeCase /// /// Base class for activities that send HTTP requests. /// -public abstract class SendHttpRequestBase : Activity +public abstract class SendHttpRequestBase : Activity { /// /// The URL to send the request to. diff --git a/src/modules/Elsa.Http/Features/HttpFeature.cs b/src/modules/Elsa.Http/Features/HttpFeature.cs index d3c5f7109..28217c205 100644 --- a/src/modules/Elsa.Http/Features/HttpFeature.cs +++ b/src/modules/Elsa.Http/Features/HttpFeature.cs @@ -69,6 +69,7 @@ public class HttpFeature : FeatureBase typeof(RouteData), typeof(HttpRequest), typeof(HttpResponse), + typeof(HttpResponseMessage), typeof(HttpRequestHeaders) }, "HTTP"); diff --git a/src/modules/Elsa.Workflows.Runtime/Services/AmbientActivityContext.cs b/src/modules/Elsa.Workflows.Runtime/Services/AmbientActivityContext.cs deleted file mode 100644 index f0b3a2c3d..000000000 --- a/src/modules/Elsa.Workflows.Runtime/Services/AmbientActivityContext.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Elsa.Workflows.Runtime.Services; - -/// -/// Provides ambient context for activities. -/// -internal static class AmbientActivityContext -{ - private static readonly AsyncLocal IsDetachedState = new(); - - /// - /// Gets or sets a value indicating whether the current activity is detached. - /// - public static bool IsDetached - { - get => IsDetachedState.Value; - set => IsDetachedState.Value = value; - } -} \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Runtime/Services/DefaultBackgroundActivityInvoker.cs b/src/modules/Elsa.Workflows.Runtime/Services/DefaultBackgroundActivityInvoker.cs index 5ae61fd98..12f34a11a 100644 --- a/src/modules/Elsa.Workflows.Runtime/Services/DefaultBackgroundActivityInvoker.cs +++ b/src/modules/Elsa.Workflows.Runtime/Services/DefaultBackgroundActivityInvoker.cs @@ -1,6 +1,7 @@ using Elsa.Common.Models; using Elsa.Workflows.Core.Contracts; using Elsa.Workflows.Core.Models; +using Elsa.Workflows.Core.Services; using Elsa.Workflows.Runtime.Contracts; using Elsa.Workflows.Runtime.Middleware.Activities; using Elsa.Workflows.Runtime.Models; @@ -73,19 +74,38 @@ public class DefaultBackgroundActivityInvoker : IBackgroundActivityInvoker // Invoke the activity. await _activityInvoker.InvokeAsync(activityExecutionContext); - // Capture any activity output produced by the activity. + // Capture any activity output produced by the activity (but only if the associated memory block is stored in the workflow itself). var outputDescriptors = activityExecutionContext.ActivityDescriptor.Outputs; var outputValues = new Dictionary(); foreach (var outputDescriptor in outputDescriptors) { var output = (Output?)outputDescriptor.ValueGetter(activityExecutionContext.Activity); - var outputValue = output != null ? activityExecutionContext.Get(output.MemoryBlockReference()) : default!; + + if(output == null) + continue; + + var memoryBlockReference = output.MemoryBlockReference(); + + if(!activityExecutionContext.ExpressionExecutionContext.TryGetBlock(memoryBlockReference, out var memoryBlock)) + continue; + + var variableMetadata = memoryBlock.Metadata as VariableBlockMetadata; + var driver = variableMetadata?.StorageDriverType; + + // We only capture output written to the workflow itself. Other drivers like blob storage, etc. will be ignored since the foreground context will be loading those. + if(driver != typeof(WorkflowStorageDriver)) + continue; + + var outputValue = activityExecutionContext.Get(memoryBlockReference); if (outputValue != null) outputValues[outputDescriptor.Name] = outputValue; } + // Persist any variables that were written to by the activity. + await _variablePersistenceManager.SaveVariablesAsync(workflowExecutionContext); + // Resume the workflow, passing along the activity output. // TODO: This approach will fail if the output is non-serializable. We need to find a way to pass the output to the workflow without serializing it. var bookmarkId = scheduledBackgroundActivity.BookmarkId;