Fix CompositeActivity behavior and update sample

This commit is contained in:
Sipke Schoorstra 2020-12-21 12:10:41 +01:00
parent 0b40eb104d
commit dd2004dd89
9 changed files with 101 additions and 24 deletions

View file

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Elsa.Converters
{
/// <summary>
/// Correctly deserializes a <see cref="Stack{T}"/> maintaining the order of the items.
/// </summary>
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<>);
}
}

View file

@ -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;
}
}
}

View file

@ -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)

View file

@ -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()

View file

@ -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
{

View file

@ -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}");
});
}
}
}

View file

@ -6,10 +6,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0"/>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\core\Elsa\Elsa.csproj"/>
<ProjectReference Include="..\..\..\core\Elsa\Elsa.csproj" />
<ProjectReference Include="..\..\..\persistence\Elsa.Persistence.YesSql\Elsa.Persistence.YesSql.csproj" />
</ItemGroup>
</Project>

View file

@ -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<PhoneCallService>()
.AddHostedService<PhoneCallWorker>()
.AddActivity<MakePhoneCall>()
.AddWorkflow<PhoneCallWorkflow>();
});
}

View file

@ -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<MakePhoneCall>()
.WriteLine("Workflow finished.");
}
}