diff --git a/src/core/Elsa.Abstractions/Converters/StackJsonConverter.cs b/src/core/Elsa.Abstractions/Converters/StackJsonConverter.cs
new file mode 100644
index 000000000..26cecb75d
--- /dev/null
+++ b/src/core/Elsa.Abstractions/Converters/StackJsonConverter.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Elsa.Converters
+{
+ ///
+ /// Correctly deserializes a maintaining the order of the items.
+ ///
+ public class StackJsonConverter : JsonConverter
+ {
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ var newSerializer = new JsonSerializer();
+ newSerializer.Serialize(writer, value);
+ }
+
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ var newSerializer = new JsonSerializer();
+ var list = newSerializer.Deserialize(reader, objectType)!;
+ return Activator.CreateInstance(objectType, list);
+ }
+
+ public override bool CanConvert(Type objectType) => objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(Stack<>);
+ }
+}
\ No newline at end of file
diff --git a/src/core/Elsa.Abstractions/Services/CompositeActivity.cs b/src/core/Elsa.Abstractions/Services/CompositeActivity.cs
index 5beaee27b..3e36b5206 100644
--- a/src/core/Elsa.Abstractions/Services/CompositeActivity.cs
+++ b/src/core/Elsa.Abstractions/Services/CompositeActivity.cs
@@ -21,12 +21,15 @@ namespace Elsa.Services
{
if (IsScheduled)
{
+ if (HasPendingChildren(context))
+ return PostSchedule(Id);
+
context.WorkflowExecutionContext.WorkflowInstance.ParentActivities.Pop();
IsScheduled = false;
return Complete(context);
}
-
- var compositeActivityBlueprint = (ICompositeActivityBlueprint)context.ActivityBlueprint;
+
+ var compositeActivityBlueprint = (ICompositeActivityBlueprint) context.ActivityBlueprint;
var startActivities = compositeActivityBlueprint.GetStartActivities().Select(x => x.Id).ToList();
context.WorkflowExecutionContext.WorkflowInstance.ParentActivities.Push(Id);
context.WorkflowExecutionContext.PostScheduleActivity(Id);
@@ -35,5 +38,14 @@ namespace Elsa.Services
}
protected virtual IActivityExecutionResult Complete(ActivityExecutionContext context) => Done();
+
+ private static bool HasPendingChildren(ActivityExecutionContext context)
+ {
+ var children = ((CompositeActivityBlueprint) context.ActivityBlueprint).Activities.Select(x => x.Id).ToList();
+ var workflowInstance = context.WorkflowExecutionContext.WorkflowInstance;
+ var hasPendingPostScheduledChildren = workflowInstance.PostScheduledActivities.Any(x => children.Contains(x.ActivityId));
+ var hasPendingScheduledChildren = workflowInstance.ScheduledActivities.Any(x => children.Contains(x.ActivityId));
+ return hasPendingPostScheduledChildren || hasPendingScheduledChildren;
+ }
}
}
\ No newline at end of file
diff --git a/src/core/Elsa.Abstractions/Services/Models/WorkflowExecutionContext.cs b/src/core/Elsa.Abstractions/Services/Models/WorkflowExecutionContext.cs
index 12627b691..e66e5c26c 100644
--- a/src/core/Elsa.Abstractions/Services/Models/WorkflowExecutionContext.cs
+++ b/src/core/Elsa.Abstractions/Services/Models/WorkflowExecutionContext.cs
@@ -97,8 +97,12 @@ namespace Elsa.Services.Models
public void SchedulePostActivities()
{
- while (HasPostScheduledActivities)
- ScheduleActivity(WorkflowInstance.PostScheduledActivities.Pop());
+ var activities = WorkflowInstance.PostScheduledActivities.Reverse();
+
+ foreach (var activity in activities)
+ ScheduleActivity(activity);
+
+ WorkflowInstance.PostScheduledActivities.Clear();
}
public object? GetOutputFrom(string activityName)
diff --git a/src/core/Elsa.Core/Serialization/DefaultContentSerializer.cs b/src/core/Elsa.Core/Serialization/DefaultContentSerializer.cs
index b4ea892e0..14204989c 100644
--- a/src/core/Elsa.Core/Serialization/DefaultContentSerializer.cs
+++ b/src/core/Elsa.Core/Serialization/DefaultContentSerializer.cs
@@ -46,6 +46,7 @@ namespace Elsa.Serialization
settings.Converters.Add(new StringEnumConverter(new DefaultNamingStrategy()));
settings.Converters.Add(new TypeJsonConverter());
settings.Converters.Add(new VersionOptionsJsonConverter());
+ settings.Converters.Add(new StackJsonConverter());
}
public static JsonSerializerSettings CreateDefaultJsonSerializationSettings()
diff --git a/src/persistence/Elsa.Persistence.YesSql/CustomJsonContentSerializer.cs b/src/persistence/Elsa.Persistence.YesSql/CustomJsonContentSerializer.cs
index 78ac03685..0d2248a5d 100644
--- a/src/persistence/Elsa.Persistence.YesSql/CustomJsonContentSerializer.cs
+++ b/src/persistence/Elsa.Persistence.YesSql/CustomJsonContentSerializer.cs
@@ -1,6 +1,7 @@
using System;
-
+using Elsa.Converters;
using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using NodaTime;
@@ -19,7 +20,13 @@ namespace Elsa.Persistence.YesSql
JsonSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
- }.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
+ };
+
+ JsonSettings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
+ JsonSettings.Converters.Add(new StackJsonConverter());
+ JsonSettings.Converters.Add(new VersionOptionsJsonConverter());
+ JsonSettings.Converters.Add(new TypeJsonConverter());
+ JsonSettings.Converters.Add(new StringEnumConverter(new DefaultNamingStrategy()));
JsonSettings.ContractResolver = new DefaultContractResolver
{
diff --git a/src/samples/worker/Elsa.Samples.WhileLoopWorker/Activities/MakePhoneCall.cs b/src/samples/worker/Elsa.Samples.WhileLoopWorker/Activities/MakePhoneCall.cs
new file mode 100644
index 000000000..062f1a180
--- /dev/null
+++ b/src/samples/worker/Elsa.Samples.WhileLoopWorker/Activities/MakePhoneCall.cs
@@ -0,0 +1,34 @@
+using Elsa.Activities.Console;
+using Elsa.Activities.ControlFlow;
+using Elsa.Activities.Timers;
+using Elsa.Builders;
+using Elsa.Samples.WhileLoopWorker.Services;
+using Elsa.Services;
+using NodaTime;
+
+namespace Elsa.Samples.WhileLoopWorker.Activities
+{
+ public class MakePhoneCall : CompositeActivity
+ {
+ private readonly PhoneCallService _phoneCallService;
+
+ public MakePhoneCall(PhoneCallService phoneCallService)
+ {
+ _phoneCallService = phoneCallService;
+ }
+
+ public override void Build(ICompositeActivityBuilder composite)
+ {
+ composite
+ .While(() => _phoneCallService.CallStatus != PhoneCallStatus.Finished,
+ @while =>
+ {
+ @while
+ .WriteLine("Ringgggg ringgg.")
+ .Timer(Duration.FromSeconds(5))
+ .Then(() => _phoneCallService.Progress())
+ .WriteLine(() => $"Call status: {_phoneCallService.CallStatus}");
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/samples/worker/Elsa.Samples.WhileLoopWorker/Elsa.Samples.WhileLoopWorker.csproj b/src/samples/worker/Elsa.Samples.WhileLoopWorker/Elsa.Samples.WhileLoopWorker.csproj
index 0c4b09476..5d05f57bb 100644
--- a/src/samples/worker/Elsa.Samples.WhileLoopWorker/Elsa.Samples.WhileLoopWorker.csproj
+++ b/src/samples/worker/Elsa.Samples.WhileLoopWorker/Elsa.Samples.WhileLoopWorker.csproj
@@ -6,10 +6,11 @@
-
+
-
+
+
diff --git a/src/samples/worker/Elsa.Samples.WhileLoopWorker/Program.cs b/src/samples/worker/Elsa.Samples.WhileLoopWorker/Program.cs
index fbf37c630..e35cd2afb 100644
--- a/src/samples/worker/Elsa.Samples.WhileLoopWorker/Program.cs
+++ b/src/samples/worker/Elsa.Samples.WhileLoopWorker/Program.cs
@@ -3,6 +3,8 @@ using Elsa.Samples.WhileLoopWorker.Workflows;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Elsa.Persistence.InMemory;
+using Elsa.Persistence.YesSql.Extensions;
+using Elsa.Samples.WhileLoopWorker.Activities;
namespace Elsa.Samples.WhileLoopWorker
{
@@ -16,11 +18,12 @@ namespace Elsa.Samples.WhileLoopWorker
(_, services) =>
{
services
- .AddElsa()
+ .AddElsa(options => options.UseYesSqlPersistence())
.AddConsoleActivities()
.AddTimerActivities()
.AddSingleton()
.AddHostedService()
+ .AddActivity()
.AddWorkflow();
});
}
diff --git a/src/samples/worker/Elsa.Samples.WhileLoopWorker/Workflows/PhoneCallWorkflow.cs b/src/samples/worker/Elsa.Samples.WhileLoopWorker/Workflows/PhoneCallWorkflow.cs
index 637c5e6b6..4f03081a2 100644
--- a/src/samples/worker/Elsa.Samples.WhileLoopWorker/Workflows/PhoneCallWorkflow.cs
+++ b/src/samples/worker/Elsa.Samples.WhileLoopWorker/Workflows/PhoneCallWorkflow.cs
@@ -1,9 +1,7 @@
using Elsa.Activities.Console;
-using Elsa.Activities.ControlFlow;
-using Elsa.Activities.Timers;
using Elsa.Builders;
+using Elsa.Samples.WhileLoopWorker.Activities;
using Elsa.Samples.WhileLoopWorker.Services;
-using NodaTime;
namespace Elsa.Samples.WhileLoopWorker.Workflows
{
@@ -23,18 +21,8 @@ namespace Elsa.Samples.WhileLoopWorker.Workflows
public void Build(IWorkflowBuilder workflow)
{
workflow
- .WriteLine("Simulating a phone call... ringgg ringgg.")
- .While(() => _phoneCallService.CallStatus != PhoneCallStatus.Finished,
- @while =>
- {
- @while
- .WriteLine("Ringgggg ringgg.")
- .WriteLine(() => $"Call status: {_phoneCallService.CallStatus}")
- .Timer(Duration.FromSeconds(5))
- .Then(() => _phoneCallService.Progress());
-
- })
- .WriteLine(() => $"Call status: {_phoneCallService.CallStatus}")
+ .WriteLine("Simulating a phone call...")
+ .Then()
.WriteLine("Workflow finished.");
}
}