Removing nested mode
This commit is contained in:
parent
1635618b01
commit
3b9d5e616e
|
|
@ -16,10 +16,9 @@ ProjectSection(SolutionItems) = preProject
|
|||
.editorconfig = .editorconfig
|
||||
.gitignore = .gitignore
|
||||
README.md = README.md
|
||||
Nuget.Config = Nuget.Config
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flowsharp.Fluid", "src\Flowsharp.Fluid\Flowsharp.Fluid.csproj", "{B20D6AF5-91B1-4455-8541-22C5B31288D0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -38,10 +37,6 @@ Global
|
|||
{48EDB976-3227-4DFD-BBB3-3BC9AEA19A88}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{48EDB976-3227-4DFD-BBB3-3BC9AEA19A88}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{48EDB976-3227-4DFD-BBB3-3BC9AEA19A88}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B20D6AF5-91B1-4455-8541-22C5B31288D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B20D6AF5-91B1-4455-8541-22C5B31288D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B20D6AF5-91B1-4455-8541-22C5B31288D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B20D6AF5-91B1-4455-8541-22C5B31288D0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -53,6 +48,5 @@ Global
|
|||
{300EE2D5-54C5-46F2-AD03-BB43589EA074} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
|
||||
{3B33AE9C-0465-4DA3-8C02-65E5766A7ED4} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
|
||||
{48EDB976-3227-4DFD-BBB3-3BC9AEA19A88} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
|
||||
{B20D6AF5-91B1-4455-8541-22C5B31288D0} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
6
Nuget.Config
Normal file
6
Nuget.Config
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<add key="NuGet" value="https://api.nuget.org/v3/index.json" />
|
||||
</packageSources>
|
||||
</configuration>
|
||||
|
|
@ -1,26 +1,16 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.ActivityResults;
|
||||
using Flowsharp.Models;
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace Flowsharp.Activities
|
||||
{
|
||||
public abstract class Activity : IActivity
|
||||
{
|
||||
public virtual string Name => GetType().Name;
|
||||
|
||||
public Task ProvideMetadataAsync(ActivityMetadataContext context, CancellationToken cancellationToken)
|
||||
{
|
||||
ProvideMetadata(context);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual Task<bool> CanExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
return Task.FromResult(CanExecute(workflowContext, activityContext));
|
||||
}
|
||||
|
||||
public virtual Task<ActivityExecutionResult> ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken)
|
||||
|
|
@ -33,11 +23,6 @@ namespace Flowsharp.Activities
|
|||
return Task.FromResult(Resume(workflowContext, activityContext));
|
||||
}
|
||||
|
||||
public virtual IEnumerable<Outcome> GetOutcomes(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext)
|
||||
{
|
||||
return Enumerable.Empty<Outcome>();
|
||||
}
|
||||
|
||||
public virtual Task OnActivityExecutedAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken)
|
||||
{
|
||||
OnActivityExecuted(workflowContext, activityContext);
|
||||
|
|
@ -80,20 +65,17 @@ namespace Flowsharp.Activities
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected virtual void ProvideMetadata(ActivityMetadataContext context)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual ActivityExecutionResult Execute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext)
|
||||
{
|
||||
return Noop();
|
||||
return ActivateEndpoint();
|
||||
}
|
||||
|
||||
protected virtual ActivityExecutionResult Resume(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext)
|
||||
{
|
||||
return Noop();
|
||||
return ActivateEndpoint();
|
||||
}
|
||||
|
||||
|
||||
protected virtual bool CanExecute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) => true;
|
||||
protected virtual void OnActivityExecuted(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) {}
|
||||
protected virtual void OnActivityExecuting(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext) {}
|
||||
protected virtual void ReceiveInput(WorkflowExecutionContext workflowContext, IDictionary<string, object> input) {}
|
||||
|
|
@ -102,32 +84,32 @@ namespace Flowsharp.Activities
|
|||
protected virtual void WorkflowStarted(WorkflowExecutionContext workflowContext) {}
|
||||
protected virtual void WorkflowStarting(WorkflowExecutionContext workflowContext) {}
|
||||
|
||||
protected IEnumerable<Outcome> Outcomes(params LocalizedString[] names)
|
||||
{
|
||||
return names.Select(x => new Outcome(x));
|
||||
}
|
||||
|
||||
protected IEnumerable<Outcome> Outcomes(IEnumerable<LocalizedString> names)
|
||||
{
|
||||
return names.Select(x => new Outcome(x));
|
||||
}
|
||||
|
||||
protected ActivityExecutionResult Outcomes(params string[] names)
|
||||
{
|
||||
return Outcomes((IEnumerable<string>)names);
|
||||
}
|
||||
|
||||
protected ActivityExecutionResult Outcomes(IEnumerable<string> names)
|
||||
{
|
||||
return new OutcomeResult(names);
|
||||
}
|
||||
|
||||
protected ActivityExecutionResult Halt()
|
||||
protected HaltResult Halt()
|
||||
{
|
||||
return new HaltResult();
|
||||
}
|
||||
|
||||
protected ActivityExecutionResult Noop()
|
||||
protected ActivateEndpointResult ActivateEndpoint(string name = null)
|
||||
{
|
||||
return new ActivateEndpointResult(new SourceEndpoint(this, name));
|
||||
}
|
||||
|
||||
protected ScheduleActivityResult ScheduleActivity(IActivity activity)
|
||||
{
|
||||
return new ScheduleActivityResult(activity);
|
||||
}
|
||||
|
||||
protected ReturnValueResult SetReturnValue(object value)
|
||||
{
|
||||
return new ReturnValueResult(value);
|
||||
}
|
||||
|
||||
protected FinishWorkflowResult Finish()
|
||||
{
|
||||
return new FinishWorkflowResult();
|
||||
}
|
||||
|
||||
protected NoopResult Noop()
|
||||
{
|
||||
return new NoopResult();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,22 +8,6 @@ namespace Flowsharp.Activities
|
|||
{
|
||||
public interface IActivity
|
||||
{
|
||||
/// <summary>
|
||||
/// The system name of the activity.
|
||||
/// </summary>
|
||||
/// <remarks>The Name is used to identify a given activity type and must be unique.</remarks>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Provides metadata about the specified activity.
|
||||
/// </summary>
|
||||
Task ProvideMetadataAsync(ActivityMetadataContext context, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of possible outcomes when the activity is executed.
|
||||
/// </summary>
|
||||
IEnumerable<Outcome> GetOutcomes(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value of whether the specified activity can execute.
|
||||
/// </summary>
|
||||
|
|
|
|||
23
src/Flowsharp.Abstractions/Activities/Workflow.cs
Normal file
23
src/Flowsharp.Abstractions/Activities/Workflow.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Flowsharp.ActivityResults;
|
||||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.Activities
|
||||
{
|
||||
public class Workflow
|
||||
{
|
||||
public Workflow()
|
||||
{
|
||||
}
|
||||
|
||||
public Workflow(IEnumerable<IActivity> activities, IEnumerable<Connection> connections)
|
||||
{
|
||||
Activities = activities.ToList();
|
||||
Connections = connections.ToList();
|
||||
}
|
||||
|
||||
public IList<IActivity> Activities { get; set; } = new List<IActivity>();
|
||||
public IList<Connection> Connections { get; set; } = new List<Connection>();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.Activities;
|
||||
using Flowsharp.Descriptors;
|
||||
using Flowsharp.Services;
|
||||
|
||||
namespace Flowsharp.ActivityProviders
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides activities based on <see cref="IActivity"/> implementations that have been registered with the service container.
|
||||
/// </summary>
|
||||
public class TypedActivityProvider : IActivityProvider
|
||||
{
|
||||
private readonly Func<IEnumerable<IActivity>> _activitiesFactory;
|
||||
|
||||
public TypedActivityProvider(Func<IEnumerable<IActivity>> activitiesFactory)
|
||||
{
|
||||
_activitiesFactory = activitiesFactory;
|
||||
}
|
||||
|
||||
public Task<IEnumerable<ActivityDescriptor>> GetActivityDescriptorsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(_activitiesFactory().Select(ToDescriptor));
|
||||
}
|
||||
|
||||
private ActivityDescriptor ToDescriptor(IActivity activity)
|
||||
{
|
||||
return new ActivityDescriptor
|
||||
{
|
||||
Name = activity.Name,
|
||||
GetMetadataAsync = activity.ProvideMetadataAsync,
|
||||
CanExecuteAsync = activity.CanExecuteAsync,
|
||||
GetOutcomes = activity.GetOutcomes,
|
||||
ExecuteActivityAsync = activity.ExecuteAsync,
|
||||
ResumeActivityAsync = activity.ResumeAsync,
|
||||
ReceiveInputAsync = activity.ReceiveInputAsync,
|
||||
WorkflowResumedAsync = activity.WorkflowResumedAsync,
|
||||
WorkflowResumingAsync = activity.WorkflowResumingAsync,
|
||||
WorkflowStartedAsync = activity.WorkflowStartedAsync,
|
||||
WorkflowStartingAsync = activity.WorkflowStartingAsync,
|
||||
OnActivityExecutedAsync = activity.OnActivityExecutedAsync,
|
||||
OnActivityExecutingAsync = activity.OnActivityExecutingAsync
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.ActivityResults
|
||||
{
|
||||
/// <summary>
|
||||
/// A result that carries information about the next activity to execute.
|
||||
/// </summary>
|
||||
public class ActivateEndpointResult : ActivityExecutionResult
|
||||
{
|
||||
public ActivateEndpointResult(SourceEndpoint endpoint)
|
||||
{
|
||||
Endpoint = endpoint;
|
||||
}
|
||||
|
||||
public SourceEndpoint Endpoint { get; }
|
||||
|
||||
protected override void Execute(WorkflowExecutionContext workflowContext)
|
||||
{
|
||||
workflowContext.ScheduleNextActivities(workflowContext, Endpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.ActivityResults
|
||||
{
|
||||
public class FinishWorkflowResult : ActivityExecutionResult
|
||||
{
|
||||
protected override void Execute(WorkflowExecutionContext workflowContext)
|
||||
{
|
||||
workflowContext.Finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,20 +11,19 @@ namespace Flowsharp.ActivityResults
|
|||
{
|
||||
public override async Task ExecuteAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
|
||||
{
|
||||
var currentActivity = workflowContext.CurrentExecutingActivity;
|
||||
var currentActivity = workflowContext.CurrentActivity;
|
||||
|
||||
if (workflowContext.IsFirstPass)
|
||||
{
|
||||
// Resume immediately when this is the first pass.
|
||||
var result = await currentActivity.ActivityDescriptor.ResumeActivityAsync(workflowContext, currentActivity, cancellationToken);
|
||||
var result = await currentActivity.ResumeAsync(workflowContext, new ActivityExecutionContext(currentActivity), cancellationToken);
|
||||
workflowContext.IsFirstPass = false;
|
||||
|
||||
await result.ExecuteAsync(workflowContext, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Block on this activity.
|
||||
workflowContext.BlockingActivities.Add(currentActivity);
|
||||
await workflowContext.HaltAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.ActivityResults
|
||||
{
|
||||
/// <summary>
|
||||
/// An activity execution result that sets the next outcomes to execute.
|
||||
/// </summary>
|
||||
public class OutcomeResult : ActivityExecutionResult
|
||||
{
|
||||
private readonly IEnumerable<string> outcomeNames;
|
||||
|
||||
public OutcomeResult(IEnumerable<string> names)
|
||||
{
|
||||
outcomeNames = names.ToList();
|
||||
}
|
||||
|
||||
protected override void Execute(WorkflowExecutionContext workflowContext)
|
||||
{
|
||||
var workflowType = workflowContext.WorkflowType;
|
||||
var currentActivity = workflowContext.CurrentExecutingActivity;
|
||||
|
||||
foreach (var outcome in outcomeNames)
|
||||
{
|
||||
// Look for next activity in the graph.
|
||||
var transition = workflowType.Transitions.FirstOrDefault(x => x.From.ActivityId == currentActivity.ActivityType.Id && x.From.OutcomeName == outcome);
|
||||
|
||||
if (transition != null)
|
||||
{
|
||||
var destinationActivity = workflowContext.Activities.Values.Single(x => x.ActivityType.Id == transition.To.ActivityId);
|
||||
workflowContext.PushScheduledActivity(destinationActivity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.ActivityResults
|
||||
{
|
||||
public class ReturnValueResult : ActivityExecutionResult
|
||||
{
|
||||
private readonly object value;
|
||||
|
||||
public ReturnValueResult(object value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
protected override void Execute(WorkflowExecutionContext workflowContext)
|
||||
{
|
||||
workflowContext.SetReturnValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using Flowsharp.Activities;
|
||||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.ActivityResults
|
||||
{
|
||||
public class ScheduleActivityResult : ActivityExecutionResult
|
||||
{
|
||||
private readonly IActivity activity;
|
||||
|
||||
public ScheduleActivityResult(IActivity activity)
|
||||
{
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
protected override void Execute(WorkflowExecutionContext workflowContext)
|
||||
{
|
||||
workflowContext.ScheduleActivity(activity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using Flowsharp.Activities;
|
||||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.Builders
|
||||
{
|
||||
public class ActivityWorkflowBuilder
|
||||
{
|
||||
private readonly IActivity activity;
|
||||
private readonly WorkflowBuilder builder;
|
||||
|
||||
public ActivityWorkflowBuilder(WorkflowBuilder builder, IActivity activity)
|
||||
{
|
||||
this.builder = builder;
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
public ActivityWorkflowBuilder Connect(IActivity target, Action<ActivityWorkflowBuilder> activityBuilder = null)
|
||||
{
|
||||
var connection = new Connection(activity, target);
|
||||
builder.Activities.Add(target);
|
||||
builder.Connections.Add(connection);
|
||||
|
||||
activityBuilder?.Invoke(new ActivityWorkflowBuilder(builder, target));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/Flowsharp.Abstractions/Builders/WorkflowBuilder.cs
Normal file
32
src/Flowsharp.Abstractions/Builders/WorkflowBuilder.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Flowsharp.Activities;
|
||||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.Builders
|
||||
{
|
||||
public class WorkflowBuilder
|
||||
{
|
||||
public WorkflowBuilder()
|
||||
{
|
||||
Activities = new List<IActivity>();
|
||||
Connections = new List<Connection>();
|
||||
}
|
||||
|
||||
public IList<IActivity> Activities { get; }
|
||||
public IList<Connection> Connections { get; }
|
||||
|
||||
public WorkflowBuilder AddActivity(IActivity activity, Action<ActivityWorkflowBuilder> builder = null)
|
||||
{
|
||||
Activities.Add(activity);
|
||||
builder?.Invoke(new ActivityWorkflowBuilder(this, activity));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Workflow Build()
|
||||
{
|
||||
return new Workflow(Activities, Connections);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.ActivityResults;
|
||||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.Descriptors
|
||||
{
|
||||
public class ActivityDescriptor
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Provides metadata about the specified activity.
|
||||
/// </summary>
|
||||
public Func<ActivityMetadataContext, CancellationToken, Task> GetMetadataAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of possible outcomes when the activity is executed.
|
||||
/// </summary>
|
||||
public Func<WorkflowExecutionContext, ActivityExecutionContext, IEnumerable<Outcome>> GetOutcomes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value of whether the specified activity can execute.
|
||||
/// </summary>
|
||||
public Func<WorkflowExecutionContext, ActivityExecutionContext, CancellationToken, Task<bool>> CanExecuteAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Executes the specified activity.
|
||||
/// </summary>
|
||||
public Func<WorkflowExecutionContext, ActivityExecutionContext, CancellationToken, Task<ActivityExecutionResult>> ExecuteActivityAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Resumes the specified activity.
|
||||
/// </summary>
|
||||
public Func<WorkflowExecutionContext, ActivityExecutionContext, CancellationToken, Task<ActivityExecutionResult>> ResumeActivityAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Executes before a workflow starts or resumes, giving activities an opportunity to read and store any values of interest.
|
||||
/// </summary>
|
||||
public Func<WorkflowExecutionContext, IDictionary<string, object>, CancellationToken, Task> ReceiveInputAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Executes when a workflow is about to start.
|
||||
/// </summary>
|
||||
public Func<WorkflowExecutionContext, CancellationToken, Task> WorkflowStartingAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Executes when a workflow has started.
|
||||
/// </summary>
|
||||
public Func<WorkflowExecutionContext, CancellationToken, Task> WorkflowStartedAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Executes when a workflow is about to be resumed.
|
||||
/// </summary>
|
||||
public Func<WorkflowExecutionContext, CancellationToken, Task> WorkflowResumingAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Executes when a workflow is resumed.
|
||||
/// </summary>
|
||||
public Func<WorkflowExecutionContext, CancellationToken, Task> WorkflowResumedAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Executes when an activity is about to be executed.
|
||||
/// </summary>
|
||||
/// <param name="activity">The activity for which the event is invoked. This is not necessarily the activity that is about to be executed.</param>
|
||||
/// <param name="activityContext">The activity context containing the activity that is the subject of the event.</param>
|
||||
public Func<WorkflowExecutionContext, ActivityExecutionContext, CancellationToken, Task> OnActivityExecutingAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called on each activity when an activity has been executed.
|
||||
/// </summary>
|
||||
/// <param name="activity">The activity for which the event is invoked. This is not necessarily the activity that is about to be executed.</param>
|
||||
/// <param name="activityContext">The activity context containing the activity that is the subject of the event.</param>
|
||||
public Func<WorkflowExecutionContext, ActivityExecutionContext, CancellationToken, Task> OnActivityExecutedAsync { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
using Flowsharp.Activities;
|
||||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.Extensions
|
||||
{
|
||||
public static class ConnectionActivityExtensions
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.Activities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Flowsharp.Extensions
|
||||
|
|
@ -10,7 +11,7 @@ namespace Flowsharp.Extensions
|
|||
/// <summary>
|
||||
/// Safely invoke methods by catching non fatal exceptions and logging them.
|
||||
/// </summary>
|
||||
public static void Invoke<TEvents>(this IEnumerable<TEvents> events, Action<TEvents> dispatch, ILogger logger)
|
||||
public static void Invoke<T>(this IEnumerable<T> events, Action<T> dispatch, ILogger logger)
|
||||
{
|
||||
foreach (var sink in events)
|
||||
{
|
||||
|
|
@ -20,7 +21,7 @@ namespace Flowsharp.Extensions
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException(ex, logger, typeof(TEvents).Name, sink.GetType().FullName);
|
||||
HandleException(ex, logger, typeof(T).Name, sink.GetType().FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -28,7 +29,7 @@ namespace Flowsharp.Extensions
|
|||
/// <summary>
|
||||
/// Safely invoke methods by catching non fatal exceptions and logging them.
|
||||
/// </summary>
|
||||
public static async Task InvokeAsync<TEvents>(this IEnumerable<TEvents> events, Func<TEvents, Task> dispatch, ILogger logger)
|
||||
public static async Task InvokeAsync<T>(this IEnumerable<T> events, Func<T, Task> dispatch, ILogger logger)
|
||||
{
|
||||
foreach (var sink in events)
|
||||
{
|
||||
|
|
@ -38,12 +39,12 @@ namespace Flowsharp.Extensions
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException(ex, logger, typeof(TEvents).Name, sink.GetType().FullName);
|
||||
HandleException(ex, logger, typeof(T).Name, sink.GetType().FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void HandleException(Exception ex, ILogger logger, string sourceType, string method)
|
||||
private static void HandleException(Exception ex, ILogger logger, string sourceType, string method)
|
||||
{
|
||||
if (ex.IsFatal())
|
||||
throw ex;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>Flowsharp</RootNamespace>
|
||||
<LangVersion>7.1</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,14 @@
|
|||
using Flowsharp.Descriptors;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Flowsharp.Activities;
|
||||
|
||||
namespace Flowsharp.Models
|
||||
{
|
||||
public class ActivityExecutionContext
|
||||
{
|
||||
public ActivityExecutionContext(ActivityType activityType, ActivityDescriptor activityDescriptor)
|
||||
public ActivityExecutionContext(IActivity activity)
|
||||
{
|
||||
ActivityType = activityType;
|
||||
ActivityDescriptor = activityDescriptor;
|
||||
State = new JObject(activityType.State);
|
||||
Activity = activity;
|
||||
}
|
||||
|
||||
public ActivityType ActivityType { get; }
|
||||
public ActivityDescriptor ActivityDescriptor { get; }
|
||||
public JObject State { get; set; }
|
||||
public IActivity Activity { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace Flowsharp.Abstractions.Models
|
||||
{
|
||||
public class ActivityMetadata
|
||||
{
|
||||
public LocalizedString DisplayName { get; set; }
|
||||
public LocalizedString Category { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
using Flowsharp.Abstractions.Models;
|
||||
|
||||
namespace Flowsharp.Models
|
||||
{
|
||||
public class ActivityMetadataContext
|
||||
{
|
||||
public ActivityMetadata Metadata { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Flowsharp.Models
|
||||
{
|
||||
public class ActivityType
|
||||
{
|
||||
public ActivityType(string id, string name, JObject state = null)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
State = state ?? new JObject();
|
||||
}
|
||||
|
||||
public string Id { get; }
|
||||
public string Name { get; }
|
||||
public JObject State { get; }
|
||||
}
|
||||
}
|
||||
28
src/Flowsharp.Abstractions/Models/Connection.cs
Normal file
28
src/Flowsharp.Abstractions/Models/Connection.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using Flowsharp.Activities;
|
||||
|
||||
namespace Flowsharp.Models
|
||||
{
|
||||
public class Connection
|
||||
{
|
||||
public Connection()
|
||||
{
|
||||
}
|
||||
|
||||
public Connection(IActivity source, IActivity target) : this(new SourceEndpoint(source), new TargetEndpoint(target))
|
||||
{
|
||||
}
|
||||
|
||||
public Connection(IActivity source, string sourceEndpointName, IActivity target) : this(new SourceEndpoint(source, sourceEndpointName), new TargetEndpoint(target))
|
||||
{
|
||||
}
|
||||
|
||||
public Connection(SourceEndpoint source, TargetEndpoint target)
|
||||
{
|
||||
Source = source;
|
||||
Target = target;
|
||||
}
|
||||
|
||||
public SourceEndpoint Source { get; set; }
|
||||
public TargetEndpoint Target { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
namespace Flowsharp.Models
|
||||
{
|
||||
public class DestinationEndpoint : Endpoint
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,18 @@
|
|||
namespace Flowsharp.Models
|
||||
using Flowsharp.Activities;
|
||||
|
||||
namespace Flowsharp.Models
|
||||
{
|
||||
public class Endpoint
|
||||
public abstract class Endpoint
|
||||
{
|
||||
public string ActivityId { get; set; }
|
||||
protected Endpoint()
|
||||
{
|
||||
}
|
||||
|
||||
protected Endpoint(IActivity activity)
|
||||
{
|
||||
Activity = activity;
|
||||
}
|
||||
|
||||
public IActivity Activity { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
using Flowsharp.Json;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Flowsharp.Models
|
||||
{
|
||||
public class Outcome
|
||||
{
|
||||
public Outcome(LocalizedString displayName) : this(displayName.Name, displayName)
|
||||
{
|
||||
}
|
||||
|
||||
public Outcome(string name, LocalizedString displayName)
|
||||
{
|
||||
Name = name;
|
||||
DisplayName = displayName;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
[JsonConverter(typeof(LocalizedStringConverter))]
|
||||
public LocalizedString DisplayName { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,18 @@
|
|||
namespace Flowsharp.Models
|
||||
using Flowsharp.Activities;
|
||||
|
||||
namespace Flowsharp.Models
|
||||
{
|
||||
public class SourceEndpoint : Endpoint
|
||||
{
|
||||
public string OutcomeName { get; set; }
|
||||
public SourceEndpoint()
|
||||
{
|
||||
}
|
||||
|
||||
public SourceEndpoint(IActivity activity, string name = null) : base(activity)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/Flowsharp.Abstractions/Models/TargetEndpoint.cs
Normal file
15
src/Flowsharp.Abstractions/Models/TargetEndpoint.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using Flowsharp.Activities;
|
||||
|
||||
namespace Flowsharp.Models
|
||||
{
|
||||
public class TargetEndpoint : Endpoint
|
||||
{
|
||||
public TargetEndpoint()
|
||||
{
|
||||
}
|
||||
|
||||
public TargetEndpoint(IActivity activity) : base(activity)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
namespace Flowsharp.Models
|
||||
{
|
||||
public class Transition
|
||||
{
|
||||
public SourceEndpoint From { get; set; }
|
||||
public DestinationEndpoint To { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +1,87 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Flowsharp.Descriptors;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.Activities;
|
||||
|
||||
namespace Flowsharp.Models
|
||||
{
|
||||
public class WorkflowExecutionContext
|
||||
{
|
||||
public WorkflowExecutionContext(IDictionary<string, ActivityDescriptor> activityDescriptorDictionary, WorkflowType workflowType, WorkflowStatus status)
|
||||
public WorkflowExecutionContext(Workflow workflow, WorkflowStatus status = WorkflowStatus.Idle)
|
||||
{
|
||||
WorkflowType = workflowType;
|
||||
Activities = workflowType.Activities.ToDictionary(x => x.Id, x => new ActivityExecutionContext(x, activityDescriptorDictionary[x.Name]));
|
||||
BlockingActivities = new List<ActivityExecutionContext>();
|
||||
Workflow = workflow;
|
||||
Status = status;
|
||||
IsFirstPass = true;
|
||||
IsFirstPass = true;
|
||||
scheduledActivities = new Stack<IActivity>();
|
||||
scopes = new Stack<WorkflowExecutionScope>();
|
||||
|
||||
scheduledActivities = new Stack<ActivityExecutionContext>();
|
||||
BeginScope();
|
||||
}
|
||||
|
||||
private readonly Stack<ActivityExecutionContext> scheduledActivities;
|
||||
private readonly Stack<IActivity> scheduledActivities;
|
||||
private readonly Stack<WorkflowExecutionScope> scopes;
|
||||
|
||||
public WorkflowType WorkflowType { get; }
|
||||
public IDictionary<string, ActivityExecutionContext> Activities { get; }
|
||||
public ICollection<ActivityExecutionContext> BlockingActivities { get; }
|
||||
public Workflow Workflow { get; }
|
||||
public WorkflowStatus Status { get; set; }
|
||||
public bool HasScheduledActivities => scheduledActivities.Any();
|
||||
public bool IsFirstPass { get; set; }
|
||||
public ActivityExecutionContext CurrentExecutingActivity { get; private set; }
|
||||
public IActivity CurrentActivity { get; private set; }
|
||||
public WorkflowExecutionScope CurrentScope { get; private set; }
|
||||
|
||||
public void PushScheduledActivity(ActivityExecutionContext activityExecutionContext)
|
||||
public void BeginScope()
|
||||
{
|
||||
scopes.Push(CurrentScope = new WorkflowExecutionScope());
|
||||
}
|
||||
|
||||
public void EndScope()
|
||||
{
|
||||
scheduledActivities.Push(activityExecutionContext);
|
||||
scopes.Pop();
|
||||
CurrentScope = scopes.Peek();
|
||||
}
|
||||
|
||||
public void ScheduleActivity(IActivity activity)
|
||||
{
|
||||
scheduledActivities.Push(activity);
|
||||
}
|
||||
|
||||
public ActivityExecutionContext PopScheduledActivity()
|
||||
public IActivity PopScheduledActivity()
|
||||
{
|
||||
return CurrentExecutingActivity = scheduledActivities.Pop();
|
||||
CurrentActivity = scheduledActivities.Pop();
|
||||
return CurrentActivity;
|
||||
}
|
||||
|
||||
public void SetReturnValue(object value)
|
||||
{
|
||||
CurrentScope.ReturnValue = value;
|
||||
}
|
||||
|
||||
public void Fault(Exception exception, ActivityExecutionContext activity)
|
||||
public void Fault(Exception exception, IActivity activity)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task HaltAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Finish()
|
||||
{
|
||||
Status = WorkflowStatus.Finished;
|
||||
}
|
||||
|
||||
public virtual void ScheduleNextActivities(WorkflowExecutionContext workflowContext, SourceEndpoint endpoint)
|
||||
{
|
||||
var completedActivity = workflowContext.CurrentActivity;
|
||||
var connections = Workflow.Connections.Where(x => x.Source.Activity == completedActivity && x.Source.Name == endpoint.Name);
|
||||
|
||||
foreach (var connection in connections)
|
||||
{
|
||||
workflowContext.ScheduleActivity(connection.Target.Activity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
25
src/Flowsharp.Abstractions/Models/WorkflowExecutionScope.cs
Normal file
25
src/Flowsharp.Abstractions/Models/WorkflowExecutionScope.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Flowsharp.Models
|
||||
{
|
||||
public class WorkflowExecutionScope
|
||||
{
|
||||
public WorkflowExecutionScope()
|
||||
{
|
||||
Variables = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public object ReturnValue { get; set; }
|
||||
public IDictionary<string, object> Variables { get; }
|
||||
|
||||
public void SetVariable(string variableName, object value)
|
||||
{
|
||||
Variables[variableName] = value;
|
||||
}
|
||||
|
||||
public T GetVariable<T>(string name)
|
||||
{
|
||||
return Variables.ContainsKey(name) ? (T)Variables[name] : default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Flowsharp.Models
|
||||
{
|
||||
public class WorkflowType
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public ICollection<ActivityType> Activities { get; set; }
|
||||
public ICollection<Transition> Transitions { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.Activities;
|
||||
|
||||
namespace Flowsharp.Services
|
||||
{
|
||||
public interface IWorkflowSerializer
|
||||
{
|
||||
Task<string> SerializeAsync(Workflow workflow, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.Descriptors;
|
||||
|
||||
namespace Flowsharp.Services
|
||||
{
|
||||
public interface IActivityLibrary
|
||||
{
|
||||
Task<IEnumerable<ActivityDescriptor>> GetActivityDescriptorsAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.Descriptors;
|
||||
|
||||
namespace Flowsharp.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementors provide available activity descriptors.
|
||||
/// </summary>
|
||||
public interface IActivityProvider
|
||||
{
|
||||
Task<IEnumerable<ActivityDescriptor>> GetActivityDescriptorsAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.Activities;
|
||||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.Services
|
||||
{
|
||||
public interface IWorkflowInvoker
|
||||
{
|
||||
Task InvokeAsync(WorkflowExecutionContext workflowContext, string startActivityId, CancellationToken cancellationToken);
|
||||
Task<WorkflowExecutionContext> InvokeAsync(Workflow workflow, IActivity startActivity = default, CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
37
src/Flowsharp.Core/Activities/IfElse.cs
Normal file
37
src/Flowsharp.Core/Activities/IfElse.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using Flowsharp.ActivityResults;
|
||||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.Activities
|
||||
{
|
||||
public class IfElse : Activity
|
||||
{
|
||||
private readonly Func<WorkflowExecutionContext, ActivityExecutionContext, bool> condition;
|
||||
|
||||
public IfElse()
|
||||
{
|
||||
}
|
||||
|
||||
public IfElse(Func<WorkflowExecutionContext, ActivityExecutionContext, bool> condition, IActivity trueBranch, IActivity falseBranch)
|
||||
{
|
||||
this.condition = condition;
|
||||
TrueBranch = trueBranch;
|
||||
FalseBranch = falseBranch;
|
||||
}
|
||||
|
||||
public IActivity TrueBranch { get; set; }
|
||||
public IActivity FalseBranch { get; set;}
|
||||
|
||||
protected override ActivityExecutionResult Execute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext)
|
||||
{
|
||||
var result = condition(workflowContext, activityContext);
|
||||
if (TrueBranch != null && result)
|
||||
return ScheduleActivity(TrueBranch);
|
||||
|
||||
if(FalseBranch != null && !result)
|
||||
return ScheduleActivity(FalseBranch);
|
||||
|
||||
return Noop();
|
||||
}
|
||||
}
|
||||
}
|
||||
30
src/Flowsharp.Core/Activities/ReadLine.cs
Normal file
30
src/Flowsharp.Core/Activities/ReadLine.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.ActivityResults;
|
||||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.Activities
|
||||
{
|
||||
public class ReadLine : Activity
|
||||
{
|
||||
private readonly TextReader input;
|
||||
|
||||
public ReadLine() : this(Console.In)
|
||||
{
|
||||
}
|
||||
|
||||
public ReadLine(TextReader input)
|
||||
{
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public override async Task<ActivityExecutionResult> ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken)
|
||||
{
|
||||
var value = await input.ReadLineAsync();
|
||||
workflowContext.SetReturnValue(value);
|
||||
return ActivateEndpoint();
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/Flowsharp.Core/Activities/SetVariable.cs
Normal file
37
src/Flowsharp.Core/Activities/SetVariable.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using Flowsharp.ActivityResults;
|
||||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.Activities
|
||||
{
|
||||
public class SetVariable : Activity
|
||||
{
|
||||
private readonly Func<WorkflowExecutionContext, ActivityExecutionContext, object> valueProvider;
|
||||
|
||||
public SetVariable()
|
||||
{
|
||||
}
|
||||
|
||||
public SetVariable(string name, Func<WorkflowExecutionContext, ActivityExecutionContext, object> valueProvider) : this(name, default(object))
|
||||
{
|
||||
VariableName = name;
|
||||
this.valueProvider = valueProvider;
|
||||
}
|
||||
|
||||
public SetVariable(string name, object value)
|
||||
{
|
||||
VariableName = name;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public string VariableName { get; set; }
|
||||
public object Value { get; set; }
|
||||
|
||||
protected override ActivityExecutionResult Execute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext)
|
||||
{
|
||||
var value = valueProvider(workflowContext, activityContext);
|
||||
workflowContext.CurrentScope.SetVariable(VariableName, value);
|
||||
return ActivateEndpoint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,54 @@
|
|||
using System;
|
||||
using Flowsharp.Activities;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.ActivityResults;
|
||||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.ActivityProviders
|
||||
namespace Flowsharp.Activities
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides activities based on <see cref="IActivity"/> implementations that have been registered with the service container.
|
||||
/// Writes a text string to the specified stream.
|
||||
/// </summary>
|
||||
public class WriteLine : Activity
|
||||
{
|
||||
protected override ActivityExecutionResult Execute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext)
|
||||
private readonly TextWriter output;
|
||||
private readonly Func<WorkflowExecutionContext, ActivityExecutionContext, string> textProvider;
|
||||
|
||||
public WriteLine() : this(Console.Out, null)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
return Outcomes("Done");
|
||||
}
|
||||
|
||||
public WriteLine(string text) : this(Console.Out, text)
|
||||
{
|
||||
}
|
||||
|
||||
public WriteLine(Func<WorkflowExecutionContext, ActivityExecutionContext, string> textProvider) : this(Console.Out, null)
|
||||
{
|
||||
this.textProvider = textProvider;
|
||||
}
|
||||
|
||||
public WriteLine(TextWriter output, string text)
|
||||
{
|
||||
this.output = output;
|
||||
Text = text;
|
||||
textProvider = (w, a) => Text;
|
||||
}
|
||||
|
||||
public string Text { get; set; }
|
||||
|
||||
protected override bool CanExecute(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext)
|
||||
{
|
||||
var text = textProvider(workflowContext, activityContext);
|
||||
return text != null;
|
||||
}
|
||||
|
||||
public override async Task<ActivityExecutionResult> ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, CancellationToken cancellationToken)
|
||||
{
|
||||
var text = textProvider(workflowContext, activityContext);
|
||||
await output.WriteLineAsync(text);
|
||||
return ActivateEndpoint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>Flowsharp</RootNamespace>
|
||||
<LangVersion>7.1</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -14,4 +15,8 @@
|
|||
<Folder Include="Models\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="YamlDotNet.NetStandard" Version="4.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
22
src/Flowsharp.Core/Serialization/JsonWorkflowSerializer.cs
Normal file
22
src/Flowsharp.Core/Serialization/JsonWorkflowSerializer.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.Activities;
|
||||
using Flowsharp.Services;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Flowsharp.Serialization
|
||||
{
|
||||
public class JsonWorkflowSerializer : IWorkflowSerializer
|
||||
{
|
||||
public Task<string> SerializeAsync(Workflow workflow, CancellationToken cancellationToken)
|
||||
{
|
||||
var settings = new JsonSerializerSettings
|
||||
{
|
||||
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
|
||||
TypeNameHandling = TypeNameHandling.Objects
|
||||
};
|
||||
var json = JsonConvert.SerializeObject(workflow, settings);
|
||||
return Task.FromResult(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.Descriptors;
|
||||
|
||||
namespace Flowsharp.Services
|
||||
{
|
||||
public class ActivityLibrary : IActivityLibrary
|
||||
{
|
||||
private readonly IEnumerable<IActivityProvider> providers;
|
||||
|
||||
public ActivityLibrary(IEnumerable<IActivityProvider> providers)
|
||||
{
|
||||
this.providers = providers;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ActivityDescriptor>> GetActivityDescriptorsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var tasks = providers.Select(x => x.GetActivityDescriptorsAsync(cancellationToken)).ToList();
|
||||
var results = await Task.WhenAll(tasks);
|
||||
|
||||
return results.SelectMany(x => x);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ActivityLibraryExtensions
|
||||
{
|
||||
public static async Task<IDictionary<string, ActivityDescriptor>> GetActivityDescriptorDictionaryAsync(this IActivityLibrary activityLibrary, CancellationToken cancellationToken)
|
||||
{
|
||||
var activityDescriptors = await activityLibrary.GetActivityDescriptorsAsync(cancellationToken);
|
||||
return activityDescriptors.ToDictionary(x => x.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.Activities;
|
||||
using Flowsharp.ActivityResults;
|
||||
using Flowsharp.Extensions;
|
||||
using Flowsharp.Models;
|
||||
|
|
@ -18,82 +20,87 @@ namespace Flowsharp.Services
|
|||
|
||||
private readonly ILogger logger;
|
||||
|
||||
public async Task InvokeAsync(WorkflowExecutionContext workflowContext, string startActivityId, CancellationToken cancellationToken)
|
||||
public async Task<WorkflowExecutionContext> InvokeAsync(Workflow workflow, IActivity startActivity = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var isResuming = workflowContext.Status == WorkflowStatus.Resuming;
|
||||
var startActivity = workflowContext.Activities[startActivityId];
|
||||
var workflowExecutionContext = new WorkflowExecutionContext(workflow);
|
||||
var isResuming = workflowExecutionContext.Status == WorkflowStatus.Resuming;
|
||||
|
||||
workflowContext.Status = WorkflowStatus.Executing;
|
||||
workflowContext.PushScheduledActivity(startActivity);
|
||||
|
||||
while (workflowContext.HasScheduledActivities)
|
||||
if (startActivity == null)
|
||||
startActivity = workflow.Activities.First();
|
||||
|
||||
workflowExecutionContext.Status = WorkflowStatus.Executing;
|
||||
workflowExecutionContext.ScheduleActivity(startActivity);
|
||||
await InvokeActivitiesAsync(workflowExecutionContext, x => x.WorkflowStartingAsync(workflowExecutionContext, cancellationToken));
|
||||
|
||||
while (workflowExecutionContext.HasScheduledActivities)
|
||||
{
|
||||
var currentActivity = workflowContext.PopScheduledActivity();
|
||||
var currentActivity = workflowExecutionContext.PopScheduledActivity();
|
||||
var result = await ExecuteActivityAsync(workflowExecutionContext, currentActivity, isResuming, cancellationToken);
|
||||
|
||||
if (!await ExecuteActivityAsync(workflowContext, currentActivity, isResuming, cancellationToken))
|
||||
if(result == null)
|
||||
break;
|
||||
|
||||
await result.ExecuteAsync(workflowExecutionContext, cancellationToken);
|
||||
|
||||
workflowContext.IsFirstPass = false;
|
||||
workflowExecutionContext.IsFirstPass = false;
|
||||
isResuming = false;
|
||||
}
|
||||
|
||||
workflowContext.Status = workflowContext.BlockingActivities.Any() ? WorkflowStatus.Halted : WorkflowStatus.Finished;
|
||||
workflowExecutionContext.Status = WorkflowStatus.Finished;
|
||||
|
||||
return workflowExecutionContext;
|
||||
}
|
||||
|
||||
private async Task<bool> ExecuteActivityAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, bool isResuming, CancellationToken cancellationToken)
|
||||
private async Task<ActivityExecutionResult> ExecuteActivityAsync(WorkflowExecutionContext workflowContext, IActivity activity, bool isResuming, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
await InvokeActivitiesAsync(workflowContext, x => x.ActivityDescriptor.OnActivityExecutingAsync(workflowContext, activityContext, cancellationToken));
|
||||
//await InvokeActivitiesAsync(workflowContext, x => x.ActivityDescriptor.OnActivityExecutingAsync(workflowContext, activity, cancellationToken));
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
workflowContext.Status = WorkflowStatus.Aborted;
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = await ExecuteOrResumeActivityAsync(workflowContext, activityContext, isResuming, cancellationToken);
|
||||
await InvokeActivitiesAsync(workflowContext, x => x.ActivityDescriptor.OnActivityExecutedAsync(workflowContext, activityContext, cancellationToken));
|
||||
await result.ExecuteAsync(workflowContext, cancellationToken);
|
||||
return await ExecuteOrResumeActivityAsync(workflowContext, activity, isResuming, cancellationToken);
|
||||
//await InvokeActivitiesAsync(workflowContext, x => x.ActivityDescriptor.OnActivityExecutedAsync(workflowContext, activity, cancellationToken));
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
FaultWorkflow(workflowContext, activityContext, ex);
|
||||
FaultWorkflow(workflowContext, activity, ex);
|
||||
}
|
||||
|
||||
return true;
|
||||
return null;
|
||||
}
|
||||
|
||||
private void FaultWorkflow(WorkflowExecutionContext workflowContext, ActivityExecutionContext activityContext, Exception ex)
|
||||
private void FaultWorkflow(WorkflowExecutionContext workflowContext, IActivity activity, Exception ex)
|
||||
{
|
||||
logger.LogError(
|
||||
ex,
|
||||
"An unhandled error occurred while executing an activity. Workflow ID: '{WorkflowTypeId}'. Activity: '{ActivityId}', '{ActivityName}'. Putting the workflow in the faulted state.",
|
||||
workflowContext.WorkflowType.Name,
|
||||
activityContext.ActivityType.Id,
|
||||
activityContext.ActivityType.Name
|
||||
"An unhandled error occurred while executing an activity. Putting the workflow in the faulted state."
|
||||
);
|
||||
workflowContext.Fault(ex, activityContext);
|
||||
workflowContext.Fault(ex, activity);
|
||||
}
|
||||
|
||||
private async Task<ActivityExecutionResult> ExecuteOrResumeActivityAsync(WorkflowExecutionContext workflowContext, ActivityExecutionContext activity, bool isResuming, CancellationToken cancellationToken)
|
||||
private async Task<ActivityExecutionResult> ExecuteOrResumeActivityAsync(WorkflowExecutionContext workflowContext, IActivity activity, bool isResuming, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!isResuming)
|
||||
{
|
||||
// Execute the current activity.
|
||||
return await activity.ActivityDescriptor.ExecuteActivityAsync(workflowContext, activity, cancellationToken);
|
||||
return await activity.ExecuteAsync(workflowContext, new ActivityExecutionContext(activity), cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Resume the current activity.
|
||||
return await activity.ActivityDescriptor.ResumeActivityAsync(workflowContext, activity, cancellationToken);
|
||||
return await activity.ResumeAsync(workflowContext, new ActivityExecutionContext(activity), cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InvokeActivitiesAsync(WorkflowExecutionContext workflowContext, Func<ActivityExecutionContext, Task> action)
|
||||
private async Task InvokeActivitiesAsync(WorkflowExecutionContext workflowContext, Func<IActivity, Task> action)
|
||||
{
|
||||
await workflowContext.Activities.Values.InvokeAsync(action, logger);
|
||||
await workflowContext.Workflow.Activities.InvokeAsync(action, logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Flowsharp.Abstractions\Flowsharp.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Flowsharp.Models;
|
||||
|
||||
namespace Flowsharp.Fluid
|
||||
{
|
||||
public class WorkflowBuilder
|
||||
{
|
||||
public WorkflowBuilder()
|
||||
{
|
||||
activityTypes = new List<ActivityType>();
|
||||
}
|
||||
|
||||
private IList<ActivityType> activityTypes;
|
||||
|
||||
}
|
||||
}
|
||||
0
src/Flowsharp.Samples.Console/Flowchart1.yaml
Normal file
0
src/Flowsharp.Samples.Console/Flowchart1.yaml
Normal file
|
|
@ -1,8 +1,9 @@
|
|||
using System.Threading;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flowsharp.Activities;
|
||||
using Flowsharp.ActivityProviders;
|
||||
using Flowsharp.Models;
|
||||
using Flowsharp.Builders;
|
||||
using Flowsharp.Serialization;
|
||||
using Flowsharp.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
|
@ -13,22 +14,30 @@ namespace Flowsharp.Samples.Console
|
|||
{
|
||||
static async Task Main()
|
||||
{
|
||||
var workflowType = new WorkflowType
|
||||
{
|
||||
Activities = new[]
|
||||
{
|
||||
new ActivityType("1", "WriteLine")
|
||||
},
|
||||
Transitions = new Transition[0]
|
||||
};
|
||||
|
||||
var typedActivityProvider = new TypedActivityProvider(() => new IActivity[] { new WriteLine() } );
|
||||
var activityLibrary = new ActivityLibrary(new[]{ typedActivityProvider });
|
||||
var dictionary = await activityLibrary.GetActivityDescriptorDictionaryAsync(CancellationToken.None);
|
||||
var workflowContext = new WorkflowExecutionContext(dictionary, workflowType, WorkflowStatus.Idle);
|
||||
var invoker = new WorkflowInvoker(new Logger<WorkflowInvoker>(new NullLoggerFactory()));
|
||||
|
||||
var workflow = new WorkflowBuilder()
|
||||
.AddActivity(new WriteLine("You have now transitioned into a networked workflow."), helloWorld =>
|
||||
helloWorld.Connect(new WriteLine("Let's run a program."), runProgram =>
|
||||
runProgram.Connect(new WriteLine("Enter first value:"), firstValue =>
|
||||
firstValue.Connect(new ReadLine(), value1 =>
|
||||
value1.Connect(new SetVariable("x", (w, a) => int.Parse((string)w.CurrentScope.ReturnValue)), setX =>
|
||||
setX.Connect(new WriteLine("Enter second value:"), secondValue =>
|
||||
secondValue.Connect(new ReadLine(), value2 =>
|
||||
value2.Connect(new SetVariable("y", (w, a) => int.Parse((string)w.CurrentScope.ReturnValue)), setY =>
|
||||
setY.Connect(new WriteLine((w, a) =>
|
||||
{
|
||||
var x = w.CurrentScope.GetVariable<int>("x");
|
||||
var y = w.CurrentScope.GetVariable<int>("y");
|
||||
var z = x + y;
|
||||
return $"{x} + {y} = {z}";
|
||||
}))))))))))
|
||||
.Build();
|
||||
|
||||
await invoker.InvokeAsync(workflowContext, "1", CancellationToken.None);
|
||||
await invoker.InvokeAsync(workflow);
|
||||
|
||||
var serializer = new JsonWorkflowSerializer();
|
||||
var json = await serializer.SerializeAsync(workflow, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue