Incremental work on persistence

This commit is contained in:
Sipke Schoorstra 2018-10-16 15:00:25 +02:00
parent 333e09744b
commit 5cb45c154d
34 changed files with 547 additions and 13 deletions

View file

@ -19,6 +19,14 @@ EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flowsharp.Abstractions", "src\Flowsharp.Abstractions\Flowsharp.Abstractions.csproj", "{3130C574-557C-4DA2-933E-AED7A9EBE48A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flowsharp.Persistence.Abstractions", "src\Flowsharp.Persistence.Abstractions\Flowsharp.Persistence.Abstractions.csproj", "{A5829896-89C5-4C4E-ADC7-C806C8077316}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flowsharp.Persistence.InMemory", "src\Flowsharp.Persistence.InMemory\Flowsharp.Persistence.InMemory.csproj", "{E93A1A6B-708F-4DCC-A399-1B8EC7682F92}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flowsharp.Runtime", "src\Flowsharp.Runtime\Flowsharp.Runtime.csproj", "{3C1DCAA2-D77E-4F96-9899-DA8E0E0C757F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flowsharp.Runtime.Abstractions", "src\Flowsharp.Runtime.Abstractions\Flowsharp.Runtime.Abstractions.csproj", "{792362BF-D26D-46E9-8970-E5668941AA75}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -37,6 +45,22 @@ Global
{3130C574-557C-4DA2-933E-AED7A9EBE48A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3130C574-557C-4DA2-933E-AED7A9EBE48A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3130C574-557C-4DA2-933E-AED7A9EBE48A}.Release|Any CPU.Build.0 = Release|Any CPU
{A5829896-89C5-4C4E-ADC7-C806C8077316}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5829896-89C5-4C4E-ADC7-C806C8077316}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5829896-89C5-4C4E-ADC7-C806C8077316}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5829896-89C5-4C4E-ADC7-C806C8077316}.Release|Any CPU.Build.0 = Release|Any CPU
{E93A1A6B-708F-4DCC-A399-1B8EC7682F92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E93A1A6B-708F-4DCC-A399-1B8EC7682F92}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E93A1A6B-708F-4DCC-A399-1B8EC7682F92}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E93A1A6B-708F-4DCC-A399-1B8EC7682F92}.Release|Any CPU.Build.0 = Release|Any CPU
{3C1DCAA2-D77E-4F96-9899-DA8E0E0C757F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C1DCAA2-D77E-4F96-9899-DA8E0E0C757F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C1DCAA2-D77E-4F96-9899-DA8E0E0C757F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C1DCAA2-D77E-4F96-9899-DA8E0E0C757F}.Release|Any CPU.Build.0 = Release|Any CPU
{792362BF-D26D-46E9-8970-E5668941AA75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{792362BF-D26D-46E9-8970-E5668941AA75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{792362BF-D26D-46E9-8970-E5668941AA75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{792362BF-D26D-46E9-8970-E5668941AA75}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -48,5 +72,9 @@ Global
{300EE2D5-54C5-46F2-AD03-BB43589EA074} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{48EDB976-3227-4DFD-BBB3-3BC9AEA19A88} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{3130C574-557C-4DA2-933E-AED7A9EBE48A} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{A5829896-89C5-4C4E-ADC7-C806C8077316} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{E93A1A6B-708F-4DCC-A399-1B8EC7682F92} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{3C1DCAA2-D77E-4F96-9899-DA8E0E0C757F} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{792362BF-D26D-46E9-8970-E5668941AA75} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
EndGlobalSection
EndGlobal

View file

@ -2,5 +2,6 @@
{
public abstract class Activity : IActivity
{
public virtual string Name => GetType().Name;
}
}

View file

@ -2,5 +2,6 @@
{
public interface IActivity
{
string Name { get; }
}
}

View file

@ -19,16 +19,15 @@ namespace Flowsharp.Models
CurrentScope = new WorkflowExecutionScope();
Scopes = new Stack<WorkflowExecutionScope>(new[]{ CurrentScope });
Arguments = new Variables();
HaltedActivities = new List<IActivity>();
BlockingActivities = new List<IActivity>();
}
[JsonConverter(typeof(StringEnumConverter))]
public WorkflowStatus Status { get; set; }
public IList<IActivity> Activities { get; set; } = new List<IActivity>();
public IList<Connection> Connections { get; set; } = new List<Connection>();
public Stack<WorkflowExecutionScope> Scopes { get; set; }
public WorkflowExecutionScope CurrentScope { get; set; }
public Variables Arguments { get; set; }
public IList<IActivity> HaltedActivities { get; set; }
public IList<IActivity> BlockingActivities { get; set; }
}
}

View file

@ -63,9 +63,9 @@ namespace Flowsharp.Models
public Task HaltAsync(CancellationToken cancellationToken)
{
var activity = CurrentActivity;
if (!Workflow.HaltedActivities.Contains(activity))
if (!Workflow.BlockingActivities.Contains(activity))
{
Workflow.HaltedActivities.Add(activity);
Workflow.BlockingActivities.Add(activity);
}
Workflow.Status = WorkflowStatus.Halted;

View file

@ -61,7 +61,7 @@ namespace Flowsharp.Serialization.Tokenizers
Status = (WorkflowStatus)Enum.Parse(typeof(WorkflowStatus), token["status"].Value<string>()),
Activities = activityDictionary.Values.ToList(),
Connections = DeserializeConnections(token, activityDictionary).ToList(),
HaltedActivities = DeserializeHaltedActivities(token, activityDictionary).ToList(),
BlockingActivities = DeserializeHaltedActivities(token, activityDictionary).ToList(),
Scopes = new Stack<WorkflowExecutionScope>(scopeLookup.Values),
CurrentScope = scopeLookup[currentScopeId]
};
@ -110,7 +110,7 @@ namespace Flowsharp.Serialization.Tokenizers
{
var haltedActivityModels = new JArray();
foreach (var activity in workflow.HaltedActivities)
foreach (var activity in workflow.BlockingActivities)
{
var activityId = context.ActivityIdLookup[activity];
haltedActivityModels.Add(activityId);

View file

@ -27,7 +27,7 @@ namespace Flowsharp
var isResuming = workflowExecutionContext.Workflow.Status == WorkflowStatus.Resuming;
if (startActivity != null)
workflow.HaltedActivities.Remove(startActivity);
workflow.BlockingActivities.Remove(startActivity);
else
startActivity = workflow.Activities.First();

View file

@ -0,0 +1,26 @@
using Flowsharp.Persistence.Primitives;
using Flowsharp.Persistence.Specifications;
namespace Flowsharp.Persistence.Extensions
{
public static class SpecificationExtensions
{
public static ISpecification<T, TVisitor> And<T, TVisitor>(this ISpecification<T, TVisitor> left, ISpecification<T, TVisitor> right)
where TVisitor : ISpecificationVisitor<TVisitor, T>
{
return new AndSpecification<T, TVisitor>(left, right);
}
public static ISpecification<T, TVisitor> Or<T, TVisitor>(this ISpecification<T, TVisitor> left, ISpecification<T, TVisitor> right)
where TVisitor : ISpecificationVisitor<TVisitor, T>
{
return new OrSpecification<T, TVisitor>(left, right);
}
public static ISpecification<T, TVisitor> Not<T, TVisitor>(this ISpecification<T, TVisitor> specification)
where TVisitor : ISpecificationVisitor<TVisitor, T>
{
return new NotSpecification<T, TVisitor>(specification);
}
}
}

View file

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Flowsharp.Persistence</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Flowsharp.Abstractions\Flowsharp.Abstractions.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,15 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Flowsharp.Models;
using Flowsharp.Persistence.Models;
using Flowsharp.Persistence.Specifications;
namespace Flowsharp.Persistence
{
public interface IWorkflowDefinitionStore
{
Task<IEnumerable<WorkflowDefinition>> GetManyAsync(ISpecification<WorkflowDefinition, IWorkflowDefinitionSpecificationVisitor> specification, CancellationToken cancellationToken);
Task AddAsync(WorkflowDefinition value, CancellationToken cancellationToken);
}
}

View file

@ -0,0 +1,15 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Flowsharp.Persistence.Models;
using Flowsharp.Persistence.Specifications;
namespace Flowsharp.Persistence
{
public interface IWorkflowInstanceStore
{
Task<IEnumerable<WorkflowInstance>> GetManyAsync(ISpecification<WorkflowInstance, IWorkflowInstanceSpecificationVisitor> specification, CancellationToken cancellationToken);
Task AddAsync(WorkflowInstance value, CancellationToken cancellationToken);
Task UpdateAsync(WorkflowInstance value, CancellationToken cancellationToken);
}
}

View file

@ -0,0 +1,10 @@
using Flowsharp.Models;
namespace Flowsharp.Persistence.Models
{
public class WorkflowDefinition
{
public string Id { get; set; }
public Workflow Workflow { get; set; }
}
}

View file

@ -0,0 +1,11 @@
using Flowsharp.Models;
namespace Flowsharp.Persistence.Models
{
public class WorkflowInstance
{
public string Id { get; set; }
public string WorkflowDefinitionId { get; set; }
public Workflow Workflow { get; set; }
}
}

View file

@ -0,0 +1,19 @@
using Flowsharp.Persistence.Specifications;
namespace Flowsharp.Persistence.Primitives
{
public class AndSpecification<T, TVisitor> : ISpecification<T, TVisitor> where TVisitor : ISpecificationVisitor<TVisitor, T>
{
public ISpecification<T, TVisitor> Left { get; }
public ISpecification<T, TVisitor> Right { get; }
public AndSpecification(ISpecification<T, TVisitor> left, ISpecification<T, TVisitor> right)
{
Left = left;
Right = right;
}
public void Accept(TVisitor visitor) => visitor.Visit(this);
public bool IsSatisfiedBy(T obj) => Left.IsSatisfiedBy(obj) && Right.IsSatisfiedBy(obj);
}
}

View file

@ -0,0 +1,17 @@
using Flowsharp.Persistence.Specifications;
namespace Flowsharp.Persistence.Primitives
{
public class NotSpecification<T, TVisitor> : ISpecification<T, TVisitor> where TVisitor : ISpecificationVisitor<TVisitor, T>
{
public ISpecification<T, TVisitor> Specification { get; }
public NotSpecification(ISpecification<T, TVisitor> specification)
{
Specification = specification;
}
public void Accept(TVisitor visitor) => visitor.Visit(this);
public bool IsSatisfiedBy(T obj) => !Specification.IsSatisfiedBy(obj);
}
}

View file

@ -0,0 +1,19 @@
using Flowsharp.Persistence.Specifications;
namespace Flowsharp.Persistence.Primitives
{
public class OrSpecification<T, TVisitor> : ISpecification<T, TVisitor> where TVisitor : ISpecificationVisitor<TVisitor, T>
{
public ISpecification<T, TVisitor> Left { get; }
public ISpecification<T, TVisitor> Right { get; }
public OrSpecification(ISpecification<T, TVisitor> left, ISpecification<T, TVisitor> right)
{
Left = left;
Right = right;
}
public void Accept(TVisitor visitor) => visitor.Visit(this);
public bool IsSatisfiedBy(T obj) => Left.IsSatisfiedBy(obj) || Right.IsSatisfiedBy(obj);
}
}

View file

@ -0,0 +1,12 @@
namespace Flowsharp.Persistence.Specifications
{
public interface ISpecification<in T>
{
bool IsSatisfiedBy(T item);
}
public interface ISpecification<in T, in TVisitor> : ISpecification<T> where TVisitor : ISpecificationVisitor<TVisitor, T>
{
void Accept(TVisitor visitor);
}
}

View file

@ -0,0 +1,11 @@
using Flowsharp.Persistence.Primitives;
namespace Flowsharp.Persistence.Specifications
{
public interface ISpecificationVisitor<TVisitor, T> where TVisitor : ISpecificationVisitor<TVisitor, T>
{
void Visit(AndSpecification<T, TVisitor> specification);
void Visit(OrSpecification<T, TVisitor> specification);
void Visit(NotSpecification<T, TVisitor> specification);
}
}

View file

@ -0,0 +1,10 @@
using Flowsharp.Models;
using Flowsharp.Persistence.Models;
namespace Flowsharp.Persistence.Specifications
{
public interface IWorkflowDefinitionSpecificationVisitor : ISpecificationVisitor<IWorkflowDefinitionSpecificationVisitor, WorkflowDefinition>
{
void Visit(WorkflowStartsWithActivity specification);
}
}

View file

@ -0,0 +1,9 @@
using Flowsharp.Persistence.Models;
namespace Flowsharp.Persistence.Specifications
{
public interface IWorkflowInstanceSpecificationVisitor : ISpecificationVisitor<IWorkflowInstanceSpecificationVisitor, WorkflowInstance>
{
void Visit(WorkflowIsBlockedOnActivity specification);
}
}

View file

@ -0,0 +1,30 @@
using System.Linq;
using Flowsharp.Persistence.Models;
namespace Flowsharp.Persistence.Specifications
{
public class WorkflowIsBlockedOnActivity: ISpecification<WorkflowInstance, IWorkflowInstanceSpecificationVisitor>
{
public WorkflowIsBlockedOnActivity(string activityName)
{
ActivityName = activityName;
}
public string ActivityName { get; }
public bool IsSatisfiedBy(WorkflowInstance value)
{
var query =
from activity in value.Workflow.BlockingActivities
where activity.Name == ActivityName
select activity;
return query.Any();
}
public void Accept(IWorkflowInstanceSpecificationVisitor visitor)
{
visitor.Visit(this);
}
}
}

View file

@ -0,0 +1,32 @@
using System.Linq;
using Flowsharp.Models;
using Flowsharp.Persistence.Models;
namespace Flowsharp.Persistence.Specifications
{
public class WorkflowStartsWithActivity : ISpecification<WorkflowDefinition, IWorkflowDefinitionSpecificationVisitor>
{
public WorkflowStartsWithActivity(string activityName)
{
ActivityName = activityName;
}
public string ActivityName { get; }
public bool IsSatisfiedBy(WorkflowDefinition value)
{
var query =
from activity in value.Workflow.Activities
where activity.Name == ActivityName
where !value.Workflow.Connections.Select(x => x.Target.Activity).Contains(activity)
select activity;
return query.Any();
}
public void Accept(IWorkflowDefinitionSpecificationVisitor visitor)
{
visitor.Visit(this);
}
}
}

View file

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Flowsharp.Persistence.Abstractions\Flowsharp.Persistence.Abstractions.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,32 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Flowsharp.Persistence.Models;
using Flowsharp.Persistence.Specifications;
namespace Flowsharp.Persistence.InMemory
{
public class InMemoryWorkflowDefinitionStore : IWorkflowDefinitionStore
{
public InMemoryWorkflowDefinitionStore()
{
WorkflowDefinitions = new List<WorkflowDefinition>();
}
public IList<WorkflowDefinition> WorkflowDefinitions { get; }
public Task<IEnumerable<WorkflowDefinition>> GetManyAsync(ISpecification<WorkflowDefinition, IWorkflowDefinitionSpecificationVisitor> specification, CancellationToken cancellationToken)
{
var query = WorkflowDefinitions.AsQueryable().Where(x => specification.IsSatisfiedBy(x));
var matches = query.Distinct().ToList();
return Task.FromResult<IEnumerable<WorkflowDefinition>>(matches);
}
public Task AddAsync(WorkflowDefinition value, CancellationToken cancellationToken)
{
WorkflowDefinitions.Add(value);
return Task.CompletedTask;
}
}
}

View file

@ -0,0 +1,37 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Flowsharp.Persistence.Models;
using Flowsharp.Persistence.Specifications;
namespace Flowsharp.Persistence.InMemory
{
public class InMemoryWorkflowInstanceStore : IWorkflowInstanceStore
{
public InMemoryWorkflowInstanceStore()
{
WorkflowInstances = new List<WorkflowInstance>();
}
public IList<WorkflowInstance> WorkflowInstances { get; }
public Task<IEnumerable<WorkflowInstance>> GetManyAsync(ISpecification<WorkflowInstance, IWorkflowInstanceSpecificationVisitor> specification, CancellationToken cancellationToken)
{
var query = WorkflowInstances.AsQueryable().Where(x => specification.IsSatisfiedBy(x));
var matches = query.Distinct().ToList();
return Task.FromResult<IEnumerable<WorkflowInstance>>(matches);
}
public Task AddAsync(WorkflowInstance value, CancellationToken cancellationToken)
{
WorkflowInstances.Add(value);
return Task.CompletedTask;
}
public Task UpdateAsync(WorkflowInstance value, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
}

View file

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Flowsharp.Abstractions\Flowsharp.Abstractions.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,17 @@
using System.Threading;
using System.Threading.Tasks;
using Flowsharp.Models;
namespace Flowsharp.Runtime.Abstractions
{
/// <summary>
/// Provides higher-level workflow functionality, such as triggering new and halted workflows based on received stimuli.
/// </summary>
public interface IWorkflowHost
{
/// <summary>
/// Starts new workflows that start with the specified activity name and resumes halted workflows that are blocked on activities with the specified activity name.
/// </summary>
Task TriggerWorkflowAsync(string activityName, Variables arguments, CancellationToken cancellationToken);
}
}

View file

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Flowsharp.Persistence.Abstractions\Flowsharp.Persistence.Abstractions.csproj" />
<ProjectReference Include="..\Flowsharp.Runtime.Abstractions\Flowsharp.Runtime.Abstractions.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,71 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Flowsharp.Models;
using Flowsharp.Persistence;
using Flowsharp.Persistence.Models;
using Flowsharp.Persistence.Specifications;
using Flowsharp.Runtime.Abstractions;
namespace Flowsharp.Runtime
{
public class WorkflowHost : IWorkflowHost
{
private readonly IWorkflowInvoker invoker;
private readonly IWorkflowDefinitionStore workflowDefinitionStore;
private readonly IWorkflowInstanceStore workflowInstanceStore;
public WorkflowHost(IWorkflowInvoker invoker, IWorkflowDefinitionStore workflowDefinitionStore, IWorkflowInstanceStore workflowInstanceStore)
{
this.invoker = invoker;
this.workflowDefinitionStore = workflowDefinitionStore;
this.workflowInstanceStore = workflowInstanceStore;
}
public async Task TriggerWorkflowAsync(string activityName, Variables arguments, CancellationToken cancellationToken)
{
await StartNewWorkflowsAsync(activityName, arguments, cancellationToken);
await ResumeExistingWorkflowsAsync(activityName, arguments, cancellationToken);
}
private async Task StartNewWorkflowsAsync(string activityName, Variables arguments, CancellationToken cancellationToken)
{
var workflowDefinitions = await workflowDefinitionStore.GetManyAsync(new WorkflowStartsWithActivity(activityName), cancellationToken);
foreach (var workflowDefinition in workflowDefinitions)
{
var startActivities = workflowDefinition.Workflow.Activities.Where(x => x.Name == activityName && !workflowDefinition.Workflow.Connections.Select(c => c.Target.Activity).Contains(x));
foreach (var activity in startActivities)
{
var workflowContext = await invoker.InvokeAsync(workflowDefinition.Workflow, activity, arguments, cancellationToken);
var workflowInstance = new WorkflowInstance
{
WorkflowDefinitionId = workflowDefinition.Id,
Id = Guid.NewGuid().ToString(),
Workflow = workflowContext.Workflow
};
await workflowInstanceStore.AddAsync(workflowInstance, cancellationToken);
}
}
}
private async Task ResumeExistingWorkflowsAsync(string activityName, Variables arguments, CancellationToken cancellationToken)
{
var workflowInstances = await workflowInstanceStore.GetManyAsync(new WorkflowIsBlockedOnActivity(activityName), cancellationToken);
foreach (var workflowInstance in workflowInstances)
{
var blockingActivities = workflowInstance.Workflow.BlockingActivities.Where(x => x.Name == activityName).ToList();
foreach (var activity in blockingActivities)
{
await invoker.ResumeAsync(workflowInstance.Workflow, activity, arguments, cancellationToken);
await workflowInstanceStore.UpdateAsync(workflowInstance, cancellationToken);
}
}
}
}
}

View file

@ -8,6 +8,10 @@
<ItemGroup>
<ProjectReference Include="..\Flowsharp.Core\Flowsharp.Core.csproj" />
<ProjectReference Include="..\Flowsharp.Persistence.Abstractions\Flowsharp.Persistence.Abstractions.csproj" />
<ProjectReference Include="..\Flowsharp.Persistence.InMemory\Flowsharp.Persistence.InMemory.csproj" />
<ProjectReference Include="..\Flowsharp.Runtime.Abstractions\Flowsharp.Runtime.Abstractions.csproj" />
<ProjectReference Include="..\Flowsharp.Runtime\Flowsharp.Runtime.csproj" />
</ItemGroup>
<ItemGroup>

View file

@ -2,6 +2,10 @@
using System.Threading.Tasks;
using Flowsharp.Expressions;
using Flowsharp.Handlers;
using Flowsharp.Persistence;
using Flowsharp.Persistence.InMemory;
using Flowsharp.Runtime;
using Flowsharp.Runtime.Abstractions;
using Flowsharp.Samples.Console.Handlers;
using Flowsharp.Samples.Console.Programs;
using Flowsharp.Serialization;
@ -23,12 +27,13 @@ namespace Flowsharp.Samples.Console
.AddSingleton<IWorkflowInvoker, WorkflowInvoker>()
.AddSingleton<IActivityInvoker, ActivityInvoker>()
.AddSingleton<IWorkflowSerializer, WorkflowSerializer>()
.AddSingleton<ITokenFormatter, JsonTokenFormatter>()
//.AddSingleton<ITokenFormatter, JsonTokenFormatter>()
.AddSingleton<ITokenFormatter, YamlTokenFormatter>()
.AddSingleton<IWorkflowTokenizer, WorkflowTokenizer>()
.AddSingleton<ITokenizerInvoker, TokenizerInvoker>()
.AddSingleton<ITokenizer, DefaultTokenizer>()
.AddSingleton<ITokenizer, ActivityTokenizer>()
.AddSingleton<IWorkflowHost, WorkflowHost>()
.AddLogging(logging => logging.AddConsole());
services
@ -37,14 +42,20 @@ namespace Flowsharp.Samples.Console
.AddSingleton<IActivityHandler, ReadLineHandler>()
.AddSingleton<IActivityHandler, WriteLineHandler>();
services
.AddSingleton<IWorkflowDefinitionStore, InMemoryWorkflowDefinitionStore>()
.AddSingleton<IWorkflowInstanceStore, InMemoryWorkflowInstanceStore>();
services
.AddSingleton<AdditionWorkflowProgram>()
.AddSingleton<AdditionWorkflowProgramLongRunning>()
.AddSingleton<FileBasedWorkflowProgramLongRunning>();
.AddSingleton<FileBasedWorkflowProgramLongRunning>()
.AddSingleton<WorkflowHostProgram>();
var serviceProvider = services.BuildServiceProvider();
//var program = serviceProvider.GetRequiredService<AdditionWorkflowProgramLongRunning>();
var program = serviceProvider.GetRequiredService<FileBasedWorkflowProgramLongRunning>();
//var program = serviceProvider.GetRequiredService<FileBasedWorkflowProgramLongRunning>();
var program = serviceProvider.GetRequiredService<WorkflowHostProgram>();
await program.RunAsync(CancellationToken.None);
}

View file

@ -39,7 +39,7 @@ namespace Flowsharp.Samples.Console.Programs
{
var json = serializer.Serialize(workflow);
workflow = serializer.Deserialize(json);
var haltedActivity = (ReadLine)workflow.HaltedActivities.Single();
var haltedActivity = (ReadLine)workflow.BlockingActivities.Single();
var args = new Variables {{ haltedActivity.ArgumentName, System.Console.ReadLine() }};
return await workflowInvoker.ResumeAsync(workflow, haltedActivity, args, cancellationToken);

View file

@ -40,7 +40,7 @@ namespace Flowsharp.Samples.Console.Programs
private async Task<WorkflowExecutionContext> ReadAndResumeAsync(Workflow workflow, CancellationToken cancellationToken)
{
var haltedActivity = (ReadLine)workflow.HaltedActivities.Single();
var haltedActivity = (ReadLine)workflow.BlockingActivities.Single();
var args = new Variables {{ haltedActivity.ArgumentName, System.Console.ReadLine() }};
return await workflowInvoker.ResumeAsync(workflow, haltedActivity, args, cancellationToken);
}

View file

@ -0,0 +1,51 @@
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Flowsharp.Models;
using Flowsharp.Persistence;
using Flowsharp.Persistence.Models;
using Flowsharp.Runtime.Abstractions;
using Flowsharp.Samples.Console.Activities;
using Flowsharp.Serialization;
namespace Flowsharp.Samples.Console.Programs
{
public class WorkflowHostProgram
{
private readonly IWorkflowHost workflowHost;
private readonly IWorkflowSerializer serializer;
private readonly IWorkflowDefinitionStore workflowStore;
public WorkflowHostProgram(IWorkflowHost workflowHost, IWorkflowSerializer serializer, IWorkflowDefinitionStore workflowStore)
{
this.workflowHost = workflowHost;
this.serializer = serializer;
this.workflowStore = workflowStore;
}
public async Task RunAsync(CancellationToken cancellationToken)
{
var assembly = typeof(FileBasedWorkflowProgramLongRunning).Assembly;
var resource = assembly.GetManifestResourceStream("Flowsharp.Samples.Console.SampleWorkflow.yaml");
var resourceReader = new StreamReader(resource);
var data = await resourceReader.ReadToEndAsync();
var workflow = serializer.Deserialize(data);
var workflowDefinition = new WorkflowDefinition { Id = "1", Workflow = workflow};
await workflowStore.AddAsync(workflowDefinition, cancellationToken);
await workflowHost.TriggerWorkflowAsync("WriteLine", Variables.Empty, cancellationToken);
await ReadAndResumeAsync("x", cancellationToken);
await ReadAndResumeAsync("y", cancellationToken);
await ReadAndResumeAsync("tryAgain", cancellationToken);
System.Console.WriteLine(data);
}
private async Task ReadAndResumeAsync(string argName, CancellationToken cancellationToken)
{
var args = new Variables { {argName, System.Console.ReadLine()} };
await workflowHost.TriggerWorkflowAsync("ReadLine", args, cancellationToken);
}
}
}