Move completion callback logic to base Activity

This commit is contained in:
Sipke Schoorstra 2022-04-20 11:41:29 +02:00
parent 4ff2c228c4
commit 77ef383865
3 changed files with 44 additions and 28 deletions

View file

@ -13,7 +13,6 @@ public abstract class Container : Activity, IContainer
{
protected Container()
{
OnSignalReceived<ActivityCompleted>(OnChildActivityCompletedAsync);
}
protected Container(params IActivity[] activities) : this()
@ -36,23 +35,6 @@ public abstract class Container : Activity, IContainer
// Schedule children.
await ScheduleChildrenAsync(context);
// Because we override ExecuteAsync, this activity will not automatically complete.
// Instead, it's up to the derived classes to explicitly complete this activity.
}
protected virtual async ValueTask OnChildActivityCompletedAsync(ActivityCompleted signal, SignalContext context)
{
var activityExecutionContext = context.ActivityExecutionContext;
var ownerActivity = activityExecutionContext.Activity;
var childActivityExecutionContext = context.SourceActivityExecutionContext;
var childActivity = childActivityExecutionContext.Activity;
var callbackEntry = activityExecutionContext.WorkflowExecutionContext.CompletionCallbacks.FirstOrDefault(x => x.Owner.Activity == ownerActivity && x.Child == childActivity);
if (callbackEntry == null)
return;
await callbackEntry.CompletionCallback(activityExecutionContext, childActivityExecutionContext);
}
protected virtual ValueTask ScheduleChildrenAsync(ActivityExecutionContext context)

View file

@ -31,37 +31,41 @@ public class ForEach : Activity
/// </summary>
public Variable CurrentValue { get; set; } = new();
protected override void Execute(ActivityExecutionContext context)
protected override bool CompleteImplicitly => false;
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
{
// Declare looping variable.
context.ExpressionExecutionContext.Register.Declare(CurrentValue);
// Execute first iteration.
HandleIteration(context);
await HandleIteration(context);
}
private void HandleIteration(ActivityExecutionContext context)
private async Task HandleIteration(ActivityExecutionContext context)
{
var currentIndex = context.GetProperty<int>(CurrentIndexProperty);
var items = context.Get(Items)!.ToList();
if (currentIndex >= items.Count)
{
await context.CompleteActivityAsync();
return;
}
var currentItem = items[currentIndex];
CurrentValue.Set(context, currentItem);
if (Body != null)
context.PostActivity(Body, OnChildCompleted);
context.ScheduleActivity(Body, OnChildCompleted);
// Increment index.
context.UpdateProperty<int>(CurrentIndexProperty, x => x + 1);
}
private ValueTask OnChildCompleted(ActivityExecutionContext context, ActivityExecutionContext childContext)
private async ValueTask OnChildCompleted(ActivityExecutionContext context, ActivityExecutionContext childContext)
{
HandleIteration(context);
return ValueTask.CompletedTask;
await HandleIteration(context);
}
private void OnBreak(BreakSignal signal, SignalContext context)

View file

@ -8,19 +8,35 @@ namespace Elsa.Models;
public abstract class Activity : ISignalHandler
{
private readonly ICollection<SignalHandlerRegistration> _signalHandlers = new List<SignalHandlerRegistration>();
protected Activity() => TypeName = TypeNameHelper.GenerateTypeName(GetType());
protected Activity(string activityType) => TypeName = activityType;
protected Activity()
{
TypeName = TypeNameHelper.GenerateTypeName(GetType());
OnSignalReceived<ActivityCompleted>(OnChildActivityCompletedAsync);
}
protected Activity(string activityType) : this()
{
TypeName = activityType;
}
public string Id { get; set; } = default!;
public string TypeName { get; set; }
public bool CanStartWorkflow { get; set; }
public IDictionary<string, object> ApplicationProperties { get; set; } = new Dictionary<string, object>();
public IDictionary<string, object> Metadata { get; set; } = new Dictionary<string, object>();
/// <summary>
/// A value indicating whether this activity should complete automatically.
/// Default is true.
/// </summary>
protected virtual bool CompleteImplicitly => true;
protected virtual async ValueTask ExecuteAsync(ActivityExecutionContext context)
{
Execute(context);
await CompleteAsync(context);
if(CompleteImplicitly)
await CompleteAsync(context);
}
protected virtual ValueTask OnSignalReceivedAsync(object signal, SignalContext context)
@ -56,6 +72,20 @@ public abstract class Activity : ISignalHandler
return ValueTask.CompletedTask;
});
}
protected virtual async ValueTask OnChildActivityCompletedAsync(ActivityCompleted signal, SignalContext context)
{
var activityExecutionContext = context.ActivityExecutionContext;
var ownerActivity = activityExecutionContext.Activity;
var childActivityExecutionContext = context.SourceActivityExecutionContext;
var childActivity = childActivityExecutionContext.Activity;
var callbackEntry = activityExecutionContext.WorkflowExecutionContext.CompletionCallbacks.FirstOrDefault(x => x.Owner.Activity == ownerActivity && x.Child == childActivity);
if (callbackEntry == null)
return;
await callbackEntry.CompletionCallback(activityExecutionContext, childActivityExecutionContext);
}
async ValueTask IActivity.ExecuteAsync(ActivityExecutionContext context)
{