Add ability to push variables to scheduled work (#4306)
This commit is contained in:
parent
594c98e066
commit
62ae3b1f6e
|
|
@ -1,3 +1,5 @@
|
|||
using Elsa.Api.Client.Resources.WorkflowDefinitions.Models;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.WorkflowInstances.Models;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -34,4 +36,9 @@ public class ActivityExecutionContextState
|
|||
/// The evaluated values of the activity's properties.
|
||||
/// </summary>
|
||||
public IDictionary<string, object>? ActivityState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of dynamically created variables.
|
||||
/// </summary>
|
||||
public ICollection<Variable> DynamicVariables { get; set; } = new List<Variable>();
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ using Elsa.Workflows.Core.Contracts;
|
|||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
|
||||
namespace Elsa.Dapper.Modules.Runtime.Stores;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using Elsa.Workflows.Core;
|
||||
using Elsa.Workflows.Core.State;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using Elsa.EntityFrameworkCore.Common;
|
||||
using Elsa.Workflows.Core.State;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Elsa.EntityFrameworkCore.Modules.Runtime;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using Elsa.Workflows.Core.Contracts;
|
|||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
|
||||
namespace Elsa.EntityFrameworkCore.Modules.Runtime;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using Elsa.Features.Attributes;
|
|||
using Elsa.Features.Services;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Features;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.EntityFrameworkCore.Modules.Runtime;
|
||||
|
|
|
|||
|
|
@ -127,13 +127,9 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
|
||||
private static object GetVariableInScope(ExpressionExecutionContext context, string variableName)
|
||||
{
|
||||
var q = from variable in EnumerateVariablesInScope(context)
|
||||
where variable.Name == variableName
|
||||
where variable.TryGet(context, out _)
|
||||
select variable.Get(context);
|
||||
|
||||
var value = q.FirstOrDefault();
|
||||
|
||||
var variable = context.GetVariable(variableName);
|
||||
var value = variable?.Get(context);
|
||||
|
||||
return ConvertIEnumerableToArray(value);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using Elsa.MongoDb.Helpers;
|
||||
using Elsa.Workflows.Core.State;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using MongoDB.Driver;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using Elsa.Features.Services;
|
|||
using Elsa.MongoDb.Common;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Features;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.MongoDb.Modules.Runtime;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Telnyx.Attributes;
|
||||
using Elsa.Telnyx.Bookmarks;
|
||||
using Elsa.Telnyx.Client.Models;
|
||||
using Elsa.Telnyx.Client.Services;
|
||||
|
|
@ -8,7 +7,6 @@ using Elsa.Telnyx.Payloads.Call;
|
|||
using Elsa.Workflows.Core;
|
||||
using Elsa.Workflows.Core.Attributes;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Telnyx.Activities;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ using Elsa.Telnyx.Payloads.Call;
|
|||
using Elsa.Workflows.Core;
|
||||
using Elsa.Workflows.Core.Attributes;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using JetBrains.Annotations;
|
||||
using Refit;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ using Elsa.Workflows.Core;
|
|||
using Elsa.Workflows.Core.Activities.Flowchart.Attributes;
|
||||
using Elsa.Workflows.Core.Attributes;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Telnyx.Activities;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ using Elsa.Workflows.Core;
|
|||
using Elsa.Workflows.Core.Activities.Flowchart.Attributes;
|
||||
using Elsa.Workflows.Core.Attributes;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Telnyx.Activities;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using Elsa.Telnyx.Activities;
|
|||
using Elsa.Telnyx.Bookmarks;
|
||||
using Elsa.Telnyx.Events;
|
||||
using Elsa.Telnyx.Extensions;
|
||||
using Elsa.Telnyx.Payloads.Abstract;
|
||||
using Elsa.Telnyx.Payloads.Call;
|
||||
using Elsa.Workflows.Core.Helpers;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using Elsa.Telnyx.Activities;
|
|||
using Elsa.Telnyx.Bookmarks;
|
||||
using Elsa.Telnyx.Events;
|
||||
using Elsa.Telnyx.Extensions;
|
||||
using Elsa.Telnyx.Payloads.Abstract;
|
||||
using Elsa.Telnyx.Payloads.Call;
|
||||
using Elsa.Workflows.Core.Helpers;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using Elsa.Telnyx.Activities;
|
|||
using Elsa.Telnyx.Bookmarks;
|
||||
using Elsa.Telnyx.Events;
|
||||
using Elsa.Telnyx.Extensions;
|
||||
using Elsa.Telnyx.Payloads.Abstract;
|
||||
using Elsa.Telnyx.Payloads.Call;
|
||||
using Elsa.Workflows.Core.Helpers;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using Elsa.Telnyx.Activities;
|
|||
using Elsa.Telnyx.Bookmarks;
|
||||
using Elsa.Telnyx.Events;
|
||||
using Elsa.Telnyx.Extensions;
|
||||
using Elsa.Telnyx.Payloads.Abstract;
|
||||
using Elsa.Telnyx.Payloads.Call;
|
||||
using Elsa.Workflows.Core.Helpers;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using System.Runtime.CompilerServices;
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Core.Attributes;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Workflows.Core.Activities;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Elsa.Expressions.Helpers;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Core.Attributes;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
using Elsa.Workflows.Core.Memory;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using Elsa.Workflows.Core.Services;
|
||||
|
||||
namespace Elsa.Workflows.Core.Activities;
|
||||
|
||||
|
|
@ -25,7 +27,7 @@ public class ParallelForEach<T> : Activity
|
|||
/// <summary>
|
||||
/// The items to iterate.
|
||||
/// </summary>
|
||||
[Input(Description = "The items to iterate.")]
|
||||
[Input(Description = "The items to iterate through.")]
|
||||
public Input<ICollection<T>> Items { get; set; } = new(Array.Empty<T>());
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -37,17 +39,27 @@ public class ParallelForEach<T> : Activity
|
|||
/// <inheritdoc />
|
||||
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
|
||||
{
|
||||
var items = context.Get(Items)!.Reverse().ToList();
|
||||
var items = context.Get(Items)!.ToList();
|
||||
var tags = new List<Guid>();
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
// TODO: For each item, declare a new block of memory to store the item into.
|
||||
// For each item, declare a new variable the work to be scheduled.
|
||||
var variable = new Variable<T>("CurrentItem", item)
|
||||
{
|
||||
// TODO: This should be configurable, because this won't work for e.g. file streams and other non-serializable types.
|
||||
StorageDriverType = typeof(WorkflowStorageDriver)
|
||||
};
|
||||
|
||||
var variables = new List<Variable<T>>
|
||||
{
|
||||
variable
|
||||
};
|
||||
|
||||
// Schedule a body of work for each item.
|
||||
var tag = Guid.NewGuid();
|
||||
tags.Add(tag);
|
||||
await context.ScheduleActivityAsync(Body, OnChildCompleted, tag);
|
||||
await context.ScheduleActivityAsync(Body, OnChildCompleted, tag, variables);
|
||||
}
|
||||
|
||||
context.SetProperty(ScheduledTagsProperty, tags);
|
||||
|
|
@ -57,7 +69,7 @@ public class ParallelForEach<T> : Activity
|
|||
private async ValueTask OnChildCompleted(ActivityExecutionContext context, ActivityExecutionContext childContext)
|
||||
{
|
||||
var scheduledTags = context.GetProperty<List<Guid>>(ScheduledTagsProperty)!;
|
||||
var completedTag = (Guid)childContext.Tag!;
|
||||
var completedTag = childContext.Tag.ConvertTo<Guid>();
|
||||
|
||||
var completedTags = new HashSet<Guid>(context.UpdateProperty<List<Guid>>(CompletedTagsProperty, completedTags =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using Elsa.Extensions;
|
|||
using Elsa.Workflows.Core.Contracts;
|
||||
using Elsa.Workflows.Core.Memory;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using Elsa.Workflows.Core.Options;
|
||||
using Elsa.Workflows.Core.Services;
|
||||
|
||||
namespace Elsa.Workflows.Core;
|
||||
|
|
@ -87,7 +88,20 @@ public class ActivityExecutionContext : IExecutionContext
|
|||
public ExpressionExecutionContext ExpressionExecutionContext { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<Variable> Variables => (Activity as IVariableContainer)?.Variables ?? Enumerable.Empty<Variable>();
|
||||
public IEnumerable<Variable> Variables
|
||||
{
|
||||
get
|
||||
{
|
||||
var containerVariables = (Activity as IVariableContainer)?.Variables ?? Enumerable.Empty<Variable>();
|
||||
var dynamicVariables = DynamicVariables;
|
||||
return containerVariables.Concat(dynamicVariables).DistinctBy(x => x.Name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A list of variables that are dynamically added to the activity execution context.
|
||||
/// </summary>
|
||||
public ICollection<Variable> DynamicVariables { get; set; } = new List<Variable>();
|
||||
|
||||
/// <summary>
|
||||
/// The currently executing activity.
|
||||
|
|
@ -159,47 +173,49 @@ public class ActivityExecutionContext : IExecutionContext
|
|||
/// Schedules the specified activity to be executed.
|
||||
/// </summary>
|
||||
/// <param name="activity">The activity to schedule.</param>
|
||||
/// <param name="completionCallback">An optional callback that is invoked when the activity completes.</param>
|
||||
/// <param name="tag">An optional tag that can be used to identify the activity.</param>
|
||||
public async ValueTask ScheduleActivityAsync(IActivity? activity, ActivityCompletionCallback? completionCallback = default, object? tag = default)
|
||||
/// <param name="completionCallback">An optional callback to invoke when the activity completes.</param>
|
||||
/// <param name="tag">An optional tag to associate with the activity execution.</param>
|
||||
/// <param name="variables">An optional list of variables to declare with the activity execution.</param>
|
||||
public async ValueTask ScheduleActivityAsync(IActivity? activity, ActivityCompletionCallback? completionCallback, object? tag = default, IEnumerable<Variable>? variables = default)
|
||||
{
|
||||
var activityNode = activity != null ? WorkflowExecutionContext.FindNodeByActivity(activity) : default;
|
||||
await ScheduleActivityAsync(activityNode, completionCallback, tag);
|
||||
var options = new ScheduleWorkOptions(completionCallback, tag, variables);
|
||||
await ScheduleActivityAsync(activity, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedules the specified activity to be executed.
|
||||
/// </summary>
|
||||
/// <param name="activity">The activity to schedule.</param>
|
||||
/// <param name="owner">The activity execution context that owns the activity.</param>
|
||||
/// <param name="completionCallback">An optional callback that is invoked when the activity completes.</param>
|
||||
/// <param name="tag">An optional tag that can be used to identify the activity.</param>
|
||||
public async ValueTask ScheduleActivityAsync(IActivity? activity, ActivityExecutionContext owner, ActivityCompletionCallback? completionCallback = default, object? tag = default)
|
||||
/// <param name="options">The options used to schedule the activity.</param>
|
||||
public async ValueTask ScheduleActivityAsync(IActivity? activity, ScheduleWorkOptions? options = default)
|
||||
{
|
||||
var activityNode = activity != null ? WorkflowExecutionContext.FindNodeByActivity(activity) : default;
|
||||
await ScheduleActivityAsync(activityNode, this, completionCallback, tag);
|
||||
await ScheduleActivityAsync(activityNode, this, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedules the specified activity to be executed.
|
||||
/// </summary>
|
||||
/// <param name="activityNode">The activity node to schedule.</param>
|
||||
/// <param name="completionCallback">An optional callback that is invoked when the activity completes.</param>
|
||||
/// <param name="tag">An optional tag that can be used to identify the activity.</param>
|
||||
public async ValueTask ScheduleActivityAsync(ActivityNode? activityNode, ActivityCompletionCallback? completionCallback = default, object? tag = default)
|
||||
/// <param name="activity">The activity to schedule.</param>
|
||||
/// <param name="owner">The activity execution context that owns the scheduled activity.</param>
|
||||
/// <param name="options">The options used to schedule the activity.</param>
|
||||
public async ValueTask ScheduleActivityAsync(IActivity? activity, ActivityExecutionContext? owner, ScheduleWorkOptions? options = default)
|
||||
{
|
||||
await ScheduleActivityAsync(activityNode, this, completionCallback, tag);
|
||||
var activityNode = activity != null ? WorkflowExecutionContext.FindNodeByActivity(activity) : default;
|
||||
await ScheduleActivityAsync(activityNode, owner, options);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Schedules the specified activity to be executed.
|
||||
/// </summary>
|
||||
/// <param name="activityNode">The activity node to schedule.</param>
|
||||
/// <param name="owner">The activity execution context that owns the activity.</param>
|
||||
/// <param name="completionCallback">An optional callback that is invoked when the activity completes.</param>
|
||||
/// <param name="tag">An optional tag that can be used to identify the activity.</param>
|
||||
public async ValueTask ScheduleActivityAsync(ActivityNode? activityNode, ActivityExecutionContext owner, ActivityCompletionCallback? completionCallback = default, object? tag = default)
|
||||
/// <param name="owner">The activity execution context that owns the scheduled activity.</param>
|
||||
/// <param name="options">The options used to schedule the activity.</param>
|
||||
public async ValueTask ScheduleActivityAsync(ActivityNode? activityNode, ActivityExecutionContext? owner = default, ScheduleWorkOptions? options = default)
|
||||
{
|
||||
var completionCallback = options?.CompletionCallback;
|
||||
owner ??= this;
|
||||
|
||||
if (activityNode == null)
|
||||
{
|
||||
if (completionCallback != null)
|
||||
|
|
@ -209,7 +225,7 @@ public class ActivityExecutionContext : IExecutionContext
|
|||
return;
|
||||
}
|
||||
|
||||
WorkflowExecutionContext.Schedule(activityNode, owner, completionCallback, tag);
|
||||
WorkflowExecutionContext.Schedule(activityNode, owner, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -222,11 +238,24 @@ public class ActivityExecutionContext : IExecutionContext
|
|||
/// Schedules the specified activities to be executed.
|
||||
/// </summary>
|
||||
/// <param name="activities">The activities to schedule.</param>
|
||||
/// <param name="completionCallback">An optional callback that is invoked for each activity when it completes.</param>
|
||||
public async ValueTask ScheduleActivities(IEnumerable<IActivity?> activities, ActivityCompletionCallback? completionCallback = default)
|
||||
/// <param name="completionCallback">The callback to invoke when the activities complete.</param>
|
||||
/// <param name="tag">An optional tag to associate with the activity execution.</param>
|
||||
/// <param name="variables">An optional list of variables to declare with the activity execution.</param>
|
||||
public async ValueTask ScheduleActivities(IEnumerable<IActivity?> activities, ActivityCompletionCallback? completionCallback, object? tag = default, IEnumerable<Variable>? variables = default)
|
||||
{
|
||||
var options = new ScheduleWorkOptions(completionCallback, tag, variables);
|
||||
await ScheduleActivities(activities, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedules the specified activities to be executed.
|
||||
/// </summary>
|
||||
/// <param name="activities">The activities to schedule.</param>
|
||||
/// <param name="options">The options used to schedule the activities.</param>
|
||||
public async ValueTask ScheduleActivities(IEnumerable<IActivity?> activities, ScheduleWorkOptions? options = default)
|
||||
{
|
||||
foreach (var activity in activities)
|
||||
await ScheduleActivityAsync(activity, completionCallback);
|
||||
await ScheduleActivityAsync(activity, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using Elsa.Common.Contracts;
|
|||
using Elsa.Workflows.Core.Activities;
|
||||
using Elsa.Workflows.Core.Memory;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using Elsa.Workflows.Core.Options;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Workflows.Core;
|
||||
|
|
@ -122,7 +123,7 @@ public class WorkflowExecutionContext : IExecutionContext
|
|||
/// The date and time the workflow execution context was created.
|
||||
/// </summary>
|
||||
public DateTimeOffset CreatedAt { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A flattened list of <see cref="ActivityNode"/>s from the <see cref="Graph"/>.
|
||||
/// </summary>
|
||||
|
|
@ -373,16 +374,34 @@ public class WorkflowExecutionContext : IExecutionContext
|
|||
/// <summary>
|
||||
/// Creates a new <see cref="ActivityExecutionContext"/> for the specified activity.
|
||||
/// </summary>
|
||||
public ActivityExecutionContext CreateActivityExecutionContext(IActivity activity, ActivityExecutionContext? parentContext = default, object? tag = default)
|
||||
public ActivityExecutionContext CreateActivityExecutionContext(IActivity activity, ActivityInvocationOptions? options = default)
|
||||
{
|
||||
var activityDescriptor = _activityRegistry.Find(activity) ?? throw new Exception($"Activity with type {activity.Type} not found in registry");
|
||||
var tag = options?.Tag;
|
||||
var parentContext = options?.Owner;
|
||||
var parentExpressionExecutionContext = parentContext?.ExpressionExecutionContext ?? ExpressionExecutionContext;
|
||||
var properties = ExpressionExecutionContextExtensions.CreateActivityExecutionContextPropertiesFrom(this, Input);
|
||||
var memory = new MemoryRegister();
|
||||
var now = _systemClock.UtcNow;
|
||||
var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, memory, parentExpressionExecutionContext, properties, CancellationToken);
|
||||
var activityExecutionContext = new ActivityExecutionContext(this, parentContext, expressionExecutionContext, activity, activityDescriptor, now, tag, _systemClock, CancellationToken);
|
||||
var variablesToDeclare = options?.Variables ?? Array.Empty<Variable>();
|
||||
var variableContainer = new[] { activityExecutionContext.ActivityNode }.Concat(activityExecutionContext.ActivityNode.Ancestors()).FirstOrDefault(x => x.Activity is IVariableContainer)?.Activity as IVariableContainer;
|
||||
expressionExecutionContext.TransientProperties[ExpressionExecutionContextExtensions.ActivityExecutionContextKey] = activityExecutionContext;
|
||||
|
||||
if (variableContainer != null)
|
||||
{
|
||||
foreach (var variable in variablesToDeclare)
|
||||
{
|
||||
// Declare a dynamic variable on the activity execution context.
|
||||
activityExecutionContext.DynamicVariables.RemoveWhere(x => x.Name == variable.Name);
|
||||
activityExecutionContext.DynamicVariables.Add(variable);
|
||||
|
||||
// Assign the variable to the expression execution context.
|
||||
expressionExecutionContext.CreateVariable(variable.Name, variable.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return activityExecutionContext;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
using Elsa.Workflows.Core.Options;
|
||||
|
||||
namespace Elsa.Workflows.Core.Contracts;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -10,12 +12,8 @@ public interface IActivityInvoker
|
|||
/// </summary>
|
||||
/// <param name="workflowExecutionContext">The workflow execution context.</param>
|
||||
/// <param name="activity">The activity to invoke.</param>
|
||||
/// <param name="owner">The activity execution context that owns the activity.</param>
|
||||
/// <param name="tag">An optional tag to associate with the activity execution.</param>
|
||||
Task InvokeAsync(WorkflowExecutionContext workflowExecutionContext,
|
||||
IActivity activity,
|
||||
ActivityExecutionContext? owner = default,
|
||||
object? tag = default);
|
||||
/// <param name="options"></param>
|
||||
Task InvokeAsync(WorkflowExecutionContext workflowExecutionContext, IActivity activity, ActivityInvocationOptions? options = default);
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the specified activity execution context.
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public interface IExecutionContext
|
|||
ExpressionExecutionContext ExpressionExecutionContext { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns variables declared the current execution context.
|
||||
/// Returns variables declared in the current execution context.
|
||||
/// </summary>
|
||||
IEnumerable<Variable> Variables { get; }
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,4 @@
|
|||
<ProjectReference Include="..\Elsa.Expressions\Elsa.Expressions.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Bookmarks\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -230,8 +230,7 @@ public static class ActivityExecutionContextExtensions
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedules the specified activity with the provided callback.
|
||||
/// If the activity is null, the callback is invoked immediately.
|
||||
/// Schedules the specified activity.
|
||||
/// </summary>
|
||||
public static async Task ScheduleOutcomeAsync(this ActivityExecutionContext context, IActivity? activity, [CallerArgumentExpression("activity")] string portPropertyName = default!)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ public static class ExpressionExecutionContextExtensions
|
|||
public static object? Get(this ExpressionExecutionContext context, Output output) => context.GetBlock(output.MemoryBlockReference).Value;
|
||||
public static T? GetVariable<T>(this ExpressionExecutionContext context, string name) => (T?)context.GetVariable(name)?.Value;
|
||||
|
||||
private static Variable? GetVariable(this ExpressionExecutionContext context, string name)
|
||||
public static Variable? GetVariable(this ExpressionExecutionContext context, string name)
|
||||
{
|
||||
foreach (var block in context.Memory.Blocks.Where(b => b.Value.Metadata is VariableBlockMetadata))
|
||||
{
|
||||
|
|
@ -59,9 +59,13 @@ public static class ExpressionExecutionContextExtensions
|
|||
return context.ParentContext?.GetVariable(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a named variable in the context.
|
||||
/// </summary>
|
||||
public static Variable CreateVariable<T>(this ExpressionExecutionContext context, string name, T? value, Type? storageDriverType = null, Action<MemoryBlock>? configure = default)
|
||||
{
|
||||
var existingVariable = context.GetVariable(name);
|
||||
|
||||
if(existingVariable != null)
|
||||
throw new Exception($"Variable {name} already exists in the context.");
|
||||
|
||||
|
|
@ -74,17 +78,24 @@ public static class ExpressionExecutionContextExtensions
|
|||
return variable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of a named variable in the context.
|
||||
/// </summary>
|
||||
public static Variable SetVariable<T>(this ExpressionExecutionContext context, string name, T? value, Action<MemoryBlock>? configure = default)
|
||||
{
|
||||
var variable = context.GetVariable(name);
|
||||
if(variable is null)
|
||||
throw new Exception($"Variable {name} not found in the context.");
|
||||
|
||||
if(variable == null)
|
||||
return CreateVariable(context, name, value, configure: configure);
|
||||
|
||||
variable.Value = value;
|
||||
variable.Set(context, value, configure);
|
||||
return variable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the output to the specified value.
|
||||
/// </summary>
|
||||
public static void Set(this ExpressionExecutionContext context, Output? output, object? value, Action<MemoryBlock>? configure = default)
|
||||
{
|
||||
if (output != null) context.Set(output.MemoryBlockReference(), value, configure);
|
||||
|
|
@ -107,11 +118,9 @@ public static class ExpressionExecutionContextExtensions
|
|||
while (currentContext != null)
|
||||
{
|
||||
var register = currentContext.Memory;
|
||||
foreach (var entry in register.Blocks)
|
||||
{
|
||||
if (!memoryBlocks.ContainsKey(entry.Key))
|
||||
memoryBlocks.Add(entry.Key, entry.Value);
|
||||
}
|
||||
|
||||
foreach (var entry in register.Blocks)
|
||||
memoryBlocks.TryAdd(entry.Key, entry.Value);
|
||||
|
||||
currentContext = currentContext.ParentContext;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Elsa.Workflows.Core;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using Elsa.Workflows.Core.Services;
|
||||
using Elsa.Workflows.Core.Options;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.Extensions;
|
||||
|
|
@ -98,13 +98,15 @@ public static class WorkflowExecutionContextExtensions
|
|||
this WorkflowExecutionContext workflowExecutionContext,
|
||||
ActivityNode activityNode,
|
||||
ActivityExecutionContext owner,
|
||||
ActivityCompletionCallback? completionCallback = default,
|
||||
object? tag = default)
|
||||
ScheduleWorkOptions? options = default)
|
||||
{
|
||||
var activityInvoker = workflowExecutionContext.GetRequiredService<IActivityInvoker>();
|
||||
var toolVersion = workflowExecutionContext.Workflow.ToolVersion;
|
||||
var activityId = toolVersion.Major >= 3 ? activityNode.Activity.Id : activityNode.NodeId;
|
||||
var workItem = new ActivityWorkItem(activityId, owner.Id, async () => await activityInvoker.InvokeAsync(workflowExecutionContext, activityNode.Activity, owner, tag), tag);
|
||||
var tag = options?.Tag;
|
||||
var activityInvocationOptions = new ActivityInvocationOptions(owner, tag, options?.Variables);
|
||||
var workItem = new ActivityWorkItem(activityId, owner.Id, async () => await activityInvoker.InvokeAsync(workflowExecutionContext, activityNode.Activity, activityInvocationOptions), tag);
|
||||
var completionCallback = options?.CompletionCallback;
|
||||
workflowExecutionContext.Scheduler.Schedule(workItem);
|
||||
workflowExecutionContext.AddCompletionCallback(owner, activityNode, completionCallback);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
using Elsa.Workflows.Core.Memory;
|
||||
|
||||
namespace Elsa.Workflows.Core.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Represents options for invoking an activity.
|
||||
/// </summary>
|
||||
/// <param name="Owner">The activity execution context that owns this invocation.</param>
|
||||
/// <param name="Tag">An optional tag that can be used to identify the invocation.</param>
|
||||
/// <param name="Variables">The variables to declare in the activity execution context that will be created for this invocation.</param>
|
||||
public record ActivityInvocationOptions(ActivityExecutionContext? Owner, object? Tag, IEnumerable<Variable>? Variables);
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using Elsa.Workflows.Core.Memory;
|
||||
using Elsa.Workflows.Core.Services;
|
||||
|
||||
namespace Elsa.Workflows.Core.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Represents options for scheduling a work item.
|
||||
/// </summary>
|
||||
/// <param name="CompletionCallback">The callback to invoke when the work item has completed.</param>
|
||||
/// <param name="Tag">A tag that can be used to identify the work item.</param>
|
||||
/// <param name="Variables">A collection of variables to declare in the activity execution context that will be created for this work item.</param>
|
||||
public record ScheduleWorkOptions(ActivityCompletionCallback? CompletionCallback = default, object? Tag = default, IEnumerable<Variable>? Variables = default);
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using Elsa.Workflows.Core.Contracts;
|
||||
using Elsa.Workflows.Core.Options;
|
||||
|
||||
namespace Elsa.Workflows.Core.Services;
|
||||
|
||||
|
|
@ -16,13 +17,10 @@ public class ActivityInvoker : IActivityInvoker
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task InvokeAsync(WorkflowExecutionContext workflowExecutionContext,
|
||||
IActivity activity,
|
||||
ActivityExecutionContext? owner,
|
||||
object? tag)
|
||||
public async Task InvokeAsync(WorkflowExecutionContext workflowExecutionContext, IActivity activity, ActivityInvocationOptions? options = default)
|
||||
{
|
||||
// Setup an activity execution context.
|
||||
var activityExecutionContext = workflowExecutionContext.CreateActivityExecutionContext(activity, owner, tag);
|
||||
var activityExecutionContext = workflowExecutionContext.CreateActivityExecutionContext(activity, options);
|
||||
|
||||
// Add the activity context to the workflow context.
|
||||
workflowExecutionContext.AddActivityExecutionContext(activityExecutionContext);
|
||||
|
|
|
|||
|
|
@ -112,7 +112,9 @@ public class WorkflowExecutionContextMapper : IWorkflowExecutionContextMapper
|
|||
Status = activityExecutionContext.Status,
|
||||
StartedAt = activityExecutionContext.StartedAt,
|
||||
CompletedAt = activityExecutionContext.CompletedAt,
|
||||
Tag = activityExecutionContext.Tag
|
||||
Tag = activityExecutionContext.Tag,
|
||||
DynamicVariables = activityExecutionContext.DynamicVariables
|
||||
|
||||
};
|
||||
return activityExecutionContextState;
|
||||
}
|
||||
|
|
@ -135,6 +137,7 @@ public class WorkflowExecutionContextMapper : IWorkflowExecutionContextMapper
|
|||
activityExecutionContext.StartedAt = activityExecutionContextState.StartedAt;
|
||||
activityExecutionContext.CompletedAt = activityExecutionContextState.CompletedAt;
|
||||
activityExecutionContext.Tag = activityExecutionContextState.Tag;
|
||||
activityExecutionContext.DynamicVariables = activityExecutionContextState.DynamicVariables;
|
||||
|
||||
return activityExecutionContext;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
using Elsa.Workflows.Core.Memory;
|
||||
|
||||
namespace Elsa.Workflows.Core.State;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -43,6 +45,11 @@ public class ActivityExecutionContextState
|
|||
/// The evaluated values of the activity's properties.
|
||||
/// </summary>
|
||||
public IDictionary<string, object>? ActivityState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of dynamically created variables.
|
||||
/// </summary>
|
||||
public ICollection<Variable> DynamicVariables { get; set; } = new List<Variable>();
|
||||
|
||||
/// <summary>
|
||||
/// The status of the activity.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
|
||||
namespace Elsa.Workflows.Runtime.Contracts;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ using Elsa.Workflows.Runtime.Contracts;
|
|||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Handlers;
|
||||
using Elsa.Workflows.Runtime.HostedServices;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
using Elsa.Workflows.Runtime.Options;
|
||||
using Elsa.Workflows.Runtime.Providers;
|
||||
using Elsa.Workflows.Runtime.Services;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
|
||||
namespace Elsa.Workflows.Runtime.Filters;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using Elsa.Mediator.Contracts;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
|
||||
namespace Elsa.Workflows.Runtime.Notifications;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
|
||||
namespace Elsa.Workflows.Runtime.Results;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ using Elsa.Common.Services;
|
|||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
using Elsa.Workflows.Runtime.Models;
|
||||
|
||||
namespace Elsa.Workflows.Runtime.Stores;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue