Update background activity invoker to only transport workflow-stored variables

This commit is contained in:
Sipke Schoorstra 2023-04-10 15:32:40 +02:00
parent 7a09944732
commit d7c6d07c5a
4 changed files with 24 additions and 21 deletions

View file

@ -112,7 +112,7 @@ public class HttpStatusCodeCase
/// <summary>
/// Base class for activities that send HTTP requests.
/// </summary>
public abstract class SendHttpRequestBase : Activity<HttpResponse>
public abstract class SendHttpRequestBase : Activity<HttpResponseMessage>
{
/// <summary>
/// The URL to send the request to.

View file

@ -69,6 +69,7 @@ public class HttpFeature : FeatureBase
typeof(RouteData),
typeof(HttpRequest),
typeof(HttpResponse),
typeof(HttpResponseMessage),
typeof(HttpRequestHeaders)
}, "HTTP");

View file

@ -1,18 +0,0 @@
namespace Elsa.Workflows.Runtime.Services;
/// <summary>
/// Provides ambient context for activities.
/// </summary>
internal static class AmbientActivityContext
{
private static readonly AsyncLocal<bool> IsDetachedState = new();
/// <summary>
/// Gets or sets a value indicating whether the current activity is detached.
/// </summary>
public static bool IsDetached
{
get => IsDetachedState.Value;
set => IsDetachedState.Value = value;
}
}

View file

@ -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<string, object>();
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;