Merge pull request #4869 from elsa-workflows/issue(4862)

Remove Persistence of Completed Activity Execution Contexts
This commit is contained in:
Sipke Schoorstra 2024-02-03 10:31:58 +01:00 committed by GitHub
commit ff9aa54fcd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 47 additions and 27 deletions

View file

@ -10,4 +10,5 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Populator/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Postgre/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=startable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Telnyx/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Telnyx/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unschedule/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View file

@ -132,7 +132,11 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
return;
var inputs = context.GetWorkflowInputs().ToDictionary(x => x.Name);
var inputDefinitions = context.GetWorkflowExecutionContext().Workflow.Inputs;
if (!context.TryGetWorkflowExecutionContext(out var workflowExecutionContext))
return;
var inputDefinitions = workflowExecutionContext.Workflow.Inputs;
foreach (var inputDefinition in inputDefinitions)
{

View file

@ -47,7 +47,9 @@ public class QuartzWorkflowScheduler : IWorkflowScheduler
.WithIdentity(taskName)
.StartAt(at)
.Build();
await scheduler.ScheduleJob(trigger, cancellationToken);
if(!await scheduler.CheckExists(trigger.Key, cancellationToken))
await scheduler.ScheduleJob(trigger, cancellationToken);
}
/// <inheritdoc />
@ -77,7 +79,9 @@ public class QuartzWorkflowScheduler : IWorkflowScheduler
.StartAt(startAt)
.WithSimpleSchedule(schedule => schedule.WithInterval(interval).RepeatForever())
.Build();
await scheduler.ScheduleJob(trigger, cancellationToken);
if(!await scheduler.CheckExists(trigger.Key, cancellationToken))
await scheduler.ScheduleJob(trigger, cancellationToken);
}
/// <inheritdoc />
@ -99,7 +103,9 @@ public class QuartzWorkflowScheduler : IWorkflowScheduler
.UsingJobData(CreateJobDataMap(request))
.WithIdentity(taskName)
.WithCronSchedule(cronExpression).Build();
await scheduler.ScheduleJob(trigger, cancellationToken);
if(!await scheduler.CheckExists(trigger.Key, cancellationToken))
await scheduler.ScheduleJob(trigger, cancellationToken);
}
/// <inheritdoc />

View file

@ -36,9 +36,10 @@ public partial class ActivityExecutionContext
// Add an execution log entry.
AddExecutionLogEntry("Canceled", payload: JournalData, includeActivityState: true);
_cancellationRegistration.Dispose();
await _cancellationRegistration.DisposeAsync();
await this.SendSignalAsync(new CancelSignal());
// ReSharper disable once MethodSupportsCancellation
await _publisher.SendAsync(new ActivityCancelled(this));
}
}

View file

@ -310,12 +310,23 @@ public static class ExpressionExecutionContextExtensions
while (currentScope != null)
{
if (!currentScope.TryGetActivityExecutionContext(out var activityExecutionContext))
break;
{
var variables = currentScope.Memory.Blocks.Values
.Where(x => x.Metadata is VariableBlockMetadata)
.Select(x => x.Metadata as VariableBlockMetadata)
.Select(x => x!.Variable)
.ToList();
var variables = activityExecutionContext.Variables;
foreach (var variable in variables)
yield return variable;
}
else
{
var variables = activityExecutionContext.Variables;
foreach (var variable in variables)
yield return variable;
foreach (var variable in variables)
yield return variable;
}
currentScope = currentScope.ParentContext;
}
@ -413,7 +424,10 @@ public static class ExpressionExecutionContextExtensions
foreach (var output in activityDescriptor.Outputs)
{
var outputPascalName = output.Name.Pascalize();
yield return new ActivityOutputs(activity.Id, activityIdPascalName, new[] { outputPascalName });
yield return new ActivityOutputs(activity.Id, activityIdPascalName, new[]
{
outputPascalName
});
}
}
}
@ -486,7 +500,7 @@ public static class ExpressionExecutionContextExtensions
// If this is an async enumerable, return as-is.
if (obj.GetType().Name == "AsyncIListEnumerableAdapter`1")
return obj;
// Use LINQ to convert the IEnumerable to an array.
var elementType = obj.GetType().GetGenericArguments().FirstOrDefault();
@ -494,6 +508,9 @@ public static class ExpressionExecutionContextExtensions
return obj;
var toArrayMethod = typeof(Enumerable).GetMethod("ToArray")!.MakeGenericMethod(elementType);
return toArrayMethod.Invoke(null, new object[] { enumerable })!;
return toArrayMethod.Invoke(null, new object[]
{
enumerable
})!;
}
}

View file

@ -253,14 +253,9 @@ public class WorkflowStateExtractor : IWorkflowStateExtractor
private static IEnumerable<ActivityExecutionContext> GetActiveActivityExecutionContexts(IEnumerable<ActivityExecutionContext> activityExecutionContexts)
{
var contexts = activityExecutionContexts.ToList();
// // If there are any faulted contexts, keep everything so that the user can fix the issue and potentially reschedule existing instances.
// if (contexts.Any(x => x.Status == ActivityStatus.Faulted))
return contexts;
// return contexts
// .Where(x => !x.IsCompleted)
// .ToList();
// Filter out completed activity execution contexts.
// This will currently break scripts accessing activity output directly, but there's a workaround for that via variable capturing.
// We may ultimately restore direct output access, but in a different way.
return activityExecutionContexts.Where(x => !x.IsCompleted).ToList();
}
}

View file

@ -1,12 +1,8 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Threading.Tasks;
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.JavaScript.Contracts;
using Elsa.Testing.Shared;
using Jint;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
using Xunit.Abstractions;