Add Composite Activity support
This commit is contained in:
parent
8ffc3dd30d
commit
594853d45c
|
|
@ -112,6 +112,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.ContextualWork
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.RunChildWorkflowWorker", "src\samples\Elsa.Samples.RunChildWorkflowWorker\Elsa.Samples.RunChildWorkflowWorker.csproj", "{1E5E1669-AEC9-4DA9-9A3D-3D405101A246}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.CompositeActivitiesConsole", "src\samples\Elsa.Samples.CompositeActivitiesConsole\Elsa.Samples.CompositeActivitiesConsole.csproj", "{CC39E9F8-72D2-4A5B-846B-E2764DFE1C19}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -267,6 +269,10 @@ Global
|
|||
{1E5E1669-AEC9-4DA9-9A3D-3D405101A246}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1E5E1669-AEC9-4DA9-9A3D-3D405101A246}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1E5E1669-AEC9-4DA9-9A3D-3D405101A246}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CC39E9F8-72D2-4A5B-846B-E2764DFE1C19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CC39E9F8-72D2-4A5B-846B-E2764DFE1C19}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CC39E9F8-72D2-4A5B-846B-E2764DFE1C19}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CC39E9F8-72D2-4A5B-846B-E2764DFE1C19}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -319,6 +325,7 @@ Global
|
|||
{565E2F7D-1F5F-45EF-B130-BC09CB3465B1} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
|
||||
{37753BF9-9D9B-4264-AB5B-D057E467D3C5} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
|
||||
{1E5E1669-AEC9-4DA9-9A3D-3D405101A246} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
|
||||
{CC39E9F8-72D2-4A5B-846B-E2764DFE1C19} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158}
|
||||
|
|
|
|||
|
|
@ -64,9 +64,9 @@ namespace Elsa.Builders
|
|||
Func<IActivityBuilder> target,
|
||||
string outcome = OutcomeNames.Done);
|
||||
|
||||
IWorkflowBlueprint Build();
|
||||
IWorkflowBlueprint Build(IWorkflow workflow);
|
||||
IWorkflowBlueprint Build(Type workflowType);
|
||||
IWorkflowBlueprint Build<T>() where T : IWorkflow;
|
||||
IWorkflowBlueprint Build(string activityIdPrefix = "activity");
|
||||
IWorkflowBlueprint Build(IWorkflow workflow, string activityIdPrefix = "activity");
|
||||
IWorkflowBlueprint Build(Type workflowType, string activityIdPrefix = "activity");
|
||||
IWorkflowBlueprint Build<T>(string activityIdPrefix = "activity") where T : IWorkflow;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Models
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
|
@ -43,10 +44,7 @@ namespace Elsa.Services
|
|||
? provider
|
||||
: null;
|
||||
|
||||
public async ValueTask SetActivityPropertiesAsync(
|
||||
IActivity activity,
|
||||
ActivityExecutionContext activityExecutionContext,
|
||||
CancellationToken cancellationToken = default)
|
||||
public async ValueTask SetActivityPropertiesAsync(IActivity activity, ActivityExecutionContext activityExecutionContext, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var properties = activity.GetType().GetProperties().Where(IsActivityProperty).ToList();
|
||||
var providers = GetProviders(activity.Id);
|
||||
|
|
@ -64,7 +62,8 @@ namespace Elsa.Services
|
|||
}
|
||||
}
|
||||
|
||||
private bool IsActivityProperty(PropertyInfo property) =>
|
||||
property.GetCustomAttribute<ActivityPropertyAttribute>() != null;
|
||||
private bool IsActivityProperty(PropertyInfo property) => property.GetCustomAttribute<ActivityPropertyAttribute>() != null;
|
||||
public IEnumerator<KeyValuePair<string, IDictionary<string, IActivityPropertyValueProvider>>> GetEnumerator() => _providers.GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
}
|
||||
19
src/core/Elsa.Abstractions/Services/CompositeActivity.cs
Normal file
19
src/core/Elsa.Abstractions/Services/CompositeActivity.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Elsa.ActivityResults;
|
||||
using Elsa.Builders;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Services
|
||||
{
|
||||
public abstract class CompositeActivity : Activity
|
||||
{
|
||||
public abstract void Build(IWorkflowBuilder workflowBuilder);
|
||||
|
||||
protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context)
|
||||
{
|
||||
var startActivities = context.ActivityBlueprint.ChildWorkflow!.GetStartActivities().Select(x => x.Id).ToList();
|
||||
return Combine(Done(), Schedule(startActivities, null!));
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/core/Elsa.Abstractions/Services/IActivityFactory.cs
Normal file
10
src/core/Elsa.Abstractions/Services/IActivityFactory.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
using Elsa.Models;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Services
|
||||
{
|
||||
public interface IActivityFactory
|
||||
{
|
||||
ActivityInstance Instantiate(IActivityBlueprint activityBlueprint);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Services
|
||||
{
|
||||
public interface IActivityPropertyProviders
|
||||
public interface IActivityPropertyProviders : IEnumerable<KeyValuePair<string, IDictionary<string, IActivityPropertyValueProvider>>>
|
||||
{
|
||||
void AddProvider(string activityId, string propertyName, IActivityPropertyValueProvider provider);
|
||||
IActivityPropertyValueProvider? GetProvider(string activityId, string propertyName);
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ namespace Elsa.Services.Models
|
|||
public string Id { get; set; } = default!;
|
||||
public string? Name { get; set; }
|
||||
public string Type { get; set; } = default!;
|
||||
|
||||
public bool PersistWorkflow { get; set; }
|
||||
public IWorkflowBlueprint? ChildWorkflow { get; set; }
|
||||
|
||||
public Func<ActivityExecutionContext, CancellationToken, ValueTask<IActivity>> CreateActivityAsync { get; set; } = default!;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,5 +11,6 @@ namespace Elsa.Services.Models
|
|||
public string Type { get; }
|
||||
public bool PersistWorkflow { get; }
|
||||
Func<ActivityExecutionContext, CancellationToken, ValueTask<IActivity>> CreateActivityAsync { get; }
|
||||
IWorkflowBlueprint? ChildWorkflow { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -5,21 +5,23 @@ using Elsa.Models;
|
|||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
using NetBox.Extensions;
|
||||
|
||||
namespace Elsa.Builders
|
||||
{
|
||||
public class WorkflowBuilder : IWorkflowBuilder
|
||||
{
|
||||
private readonly IIdGenerator _idGenerator;
|
||||
private readonly JsonSerializer _serializer;
|
||||
private readonly IActivityActivator _activityActivator;
|
||||
private readonly Func<IWorkflowBuilder> _workflowBuilderFactory;
|
||||
private readonly IList<IActivityBuilder> _activityBuilders;
|
||||
private readonly IList<IConnectionBuilder> _connectionBuilders;
|
||||
|
||||
public WorkflowBuilder(IIdGenerator idGenerator, JsonSerializer serializer, IServiceProvider serviceProvider)
|
||||
public WorkflowBuilder(IIdGenerator idGenerator, IActivityActivator activityActivator, Func<IWorkflowBuilder> workflowBuilderFactory, IServiceProvider serviceProvider)
|
||||
{
|
||||
_idGenerator = idGenerator;
|
||||
_serializer = serializer;
|
||||
_activityActivator = activityActivator;
|
||||
_workflowBuilderFactory = workflowBuilderFactory;
|
||||
ServiceProvider = serviceProvider;
|
||||
Id = idGenerator.Generate();
|
||||
Version = 1;
|
||||
|
|
@ -62,13 +64,15 @@ namespace Elsa.Builders
|
|||
}
|
||||
|
||||
public IWorkflowBuilder WithContextType<T>(WorkflowContextFidelity fidelity) => WithContextType(typeof(T), fidelity);
|
||||
|
||||
public IWorkflowBuilder WithContextType(Type type, WorkflowContextFidelity fidelity = WorkflowContextFidelity.Burst) => WithContextOptions(new WorkflowContextOptions
|
||||
{
|
||||
ContextType = type,
|
||||
ContextFidelity = fidelity
|
||||
});
|
||||
|
||||
|
||||
public IWorkflowBuilder WithContextType(Type type, WorkflowContextFidelity fidelity = WorkflowContextFidelity.Burst) =>
|
||||
WithContextOptions(
|
||||
new WorkflowContextOptions
|
||||
{
|
||||
ContextType = type,
|
||||
ContextFidelity = fidelity
|
||||
});
|
||||
|
||||
public IWorkflowBuilder WithContextOptions(WorkflowContextOptions value)
|
||||
{
|
||||
ContextOptions = value;
|
||||
|
|
@ -213,34 +217,38 @@ namespace Elsa.Builders
|
|||
where T : class, IActivity =>
|
||||
StartWith<T>(branch);
|
||||
|
||||
public IWorkflowBlueprint Build(IWorkflow workflow)
|
||||
public IWorkflowBlueprint Build(IWorkflow workflow, string activityIdPrefix = "activity")
|
||||
{
|
||||
WithId(workflow.GetType().Name);
|
||||
workflow.Build(this);
|
||||
return Build();
|
||||
return Build(activityIdPrefix);
|
||||
}
|
||||
|
||||
public IWorkflowBlueprint Build()
|
||||
public IWorkflowBlueprint Build(string activityIdPrefix = "activity")
|
||||
{
|
||||
var definitionId = !string.IsNullOrWhiteSpace(Id) ? Id : _idGenerator.Generate();
|
||||
var activityBlueprints = new List<IActivityBlueprint>();
|
||||
var connections = new List<Connection>();
|
||||
var activityPropertyProviders = new Dictionary<string, IDictionary<string, IActivityPropertyValueProvider>>();
|
||||
|
||||
// Assign automatic ids to activity builders
|
||||
var index = 0;
|
||||
foreach (var activityBuilder in _activityBuilders.Where(x => string.IsNullOrWhiteSpace(x.ActivityId))) activityBuilder.ActivityId = $"activity-{++index}";
|
||||
|
||||
var activityBlueprints = _activityBuilders
|
||||
.Select(BuildActivityBlueprint)
|
||||
.ToList();
|
||||
|
||||
foreach (var activityBuilder in _activityBuilders.Where(x => string.IsNullOrWhiteSpace(x.ActivityId)))
|
||||
activityBuilder.ActivityId = $"{activityIdPrefix}-{++index}";
|
||||
|
||||
activityBlueprints.AddRange(_activityBuilders.Select(BuildActivityBlueprint));
|
||||
|
||||
// Build composite activities.
|
||||
BuildCompositeActivities(_activityBuilders, activityBlueprints, connections, activityPropertyProviders);
|
||||
|
||||
var activityBlueprintDictionary = activityBlueprints.ToDictionary(x => x.Id);
|
||||
|
||||
var connections = _connectionBuilders
|
||||
.Select(x => new Connection(activityBlueprintDictionary[x.Source().ActivityId], activityBlueprintDictionary[x.Target().ActivityId], x.Outcome))
|
||||
.ToList();
|
||||
connections.AddRange(_connectionBuilders.Select(x => new Connection(activityBlueprintDictionary[x.Source().ActivityId], activityBlueprintDictionary[x.Target().ActivityId], x.Outcome)));
|
||||
|
||||
var activityPropertyValueProviders = _activityBuilders
|
||||
activityPropertyProviders.AddRange(_activityBuilders
|
||||
.Select(x => (x.ActivityId, x.PropertyValueProviders))
|
||||
.ToDictionary(x => x.ActivityId!, x => x.PropertyValueProviders!);
|
||||
.ToDictionary(x => x.ActivityId!, x => x.PropertyValueProviders!));
|
||||
|
||||
var workflow = new WorkflowBlueprint(
|
||||
definitionId,
|
||||
|
|
@ -257,18 +265,42 @@ namespace Elsa.Builders
|
|||
DeleteCompletedInstances,
|
||||
activityBlueprints,
|
||||
connections,
|
||||
new ActivityPropertyProviders(activityPropertyValueProviders));
|
||||
new ActivityPropertyProviders(activityPropertyProviders));
|
||||
|
||||
return workflow;
|
||||
}
|
||||
|
||||
public IWorkflowBlueprint Build(Type workflowType)
|
||||
private void BuildCompositeActivities(IEnumerable<IActivityBuilder> activityBuilders, ICollection<IActivityBlueprint> activityBlueprints, ICollection<Connection> connections, IDictionary<string, IDictionary<string, IActivityPropertyValueProvider>> activityPropertyProviders)
|
||||
{
|
||||
var workflow = (IWorkflow)ActivatorUtilities.GetServiceOrCreateInstance(ServiceProvider, workflowType);
|
||||
return Build(workflow);
|
||||
var compositeActivityType = typeof(CompositeActivity);
|
||||
var compositeActivityBuilders = activityBuilders.Where(x => compositeActivityType.IsAssignableFrom(x.ActivityType)).ToList();
|
||||
|
||||
foreach (var activityBuilder in compositeActivityBuilders)
|
||||
{
|
||||
var compositeActivity = (CompositeActivity)_activityActivator.ActivateActivity(activityBuilder.ActivityType.Name);
|
||||
var workflowBuilder = _workflowBuilderFactory();
|
||||
|
||||
compositeActivity.Build(workflowBuilder);
|
||||
|
||||
var workflow = workflowBuilder.Build($"composite-{activityBuilder.ActivityId}-activity");
|
||||
var activityDictionary = workflow.Activities.ToDictionary(x => x.Id);
|
||||
|
||||
activityBlueprints.AddRange(workflow.Activities);
|
||||
connections.AddRange(workflow.Connections.Select(x => new Connection(activityDictionary[x.Source.Activity.Id], activityDictionary[x.Target.Activity.Id], x.Source.Outcome)));
|
||||
activityPropertyProviders.AddRange(workflow.ActivityPropertyProviders);
|
||||
|
||||
var compositeActivityBlueprint = activityBlueprints.Single(x => x.Id == activityBuilder.ActivityId);
|
||||
compositeActivityBlueprint.ChildWorkflow = workflow;
|
||||
}
|
||||
}
|
||||
|
||||
public IWorkflowBlueprint Build<T>() where T : IWorkflow => Build(typeof(T));
|
||||
public IWorkflowBlueprint Build(Type workflowType, string activityIdPrefix = "activity")
|
||||
{
|
||||
var workflow = (IWorkflow)ActivatorUtilities.GetServiceOrCreateInstance(ServiceProvider, workflowType);
|
||||
return Build(workflow, activityIdPrefix);
|
||||
}
|
||||
|
||||
public IWorkflowBlueprint Build<T>(string activityIdPrefix = "activity") where T : IWorkflow => Build(typeof(T), activityIdPrefix);
|
||||
|
||||
private IActivityBlueprint BuildActivityBlueprint(IActivityBuilder builder, int index) => new ActivityBlueprint(builder.ActivityId, builder.Name, builder.ActivityType.Name, builder.PersistWorkflow, builder.BuildActivityAsync());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
.AddSingleton<IWorkflowSchedulerQueue, WorkflowSchedulerQueue>()
|
||||
.AddScoped<IWorkflowRunner, WorkflowRunner>()
|
||||
.AddSingleton<IWorkflowFactory, WorkflowFactory>()
|
||||
.AddSingleton<IActivityFactory, ActivityFactory>()
|
||||
.AddSingleton<IWorkflowBlueprintMaterializer, WorkflowBlueprintMaterializer>()
|
||||
.AddScoped<IWorkflowSelector, WorkflowSelector>()
|
||||
.AddScoped<IWorkflowDefinitionManager, WorkflowDefinitionManager>()
|
||||
|
|
|
|||
15
src/core/Elsa.Core/Services/ActivityFactory.cs
Normal file
15
src/core/Elsa.Core/Services/ActivityFactory.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using Elsa.Models;
|
||||
using Elsa.Services.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Elsa.Services
|
||||
{
|
||||
public class ActivityFactory : IActivityFactory
|
||||
{
|
||||
public ActivityInstance Instantiate(IActivityBlueprint activityBlueprint) => new ActivityInstance(
|
||||
activityBlueprint.Id,
|
||||
activityBlueprint.Type,
|
||||
null,
|
||||
new JObject());
|
||||
}
|
||||
}
|
||||
|
|
@ -3,18 +3,19 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NodaTime;
|
||||
|
||||
namespace Elsa.Services
|
||||
{
|
||||
public class WorkflowFactory : IWorkflowFactory
|
||||
{
|
||||
private readonly IActivityFactory _activityFactory;
|
||||
private readonly IClock _clock;
|
||||
private readonly IIdGenerator _idGenerator;
|
||||
|
||||
public WorkflowFactory(IClock clock, IIdGenerator idGenerator)
|
||||
public WorkflowFactory(IActivityFactory activityFactory, IClock clock, IIdGenerator idGenerator)
|
||||
{
|
||||
_activityFactory = activityFactory;
|
||||
_clock = clock;
|
||||
_idGenerator = idGenerator;
|
||||
}
|
||||
|
|
@ -41,10 +42,6 @@ namespace Elsa.Services
|
|||
return Task.FromResult(workflowInstance);
|
||||
}
|
||||
|
||||
private ActivityInstance CreateInstance(IActivityBlueprint activityBlueprint) => new ActivityInstance(
|
||||
activityBlueprint.Id,
|
||||
activityBlueprint.Type,
|
||||
null,
|
||||
new JObject());
|
||||
private ActivityInstance CreateInstance(IActivityBlueprint activityBlueprint) => _activityFactory.Instantiate(activityBlueprint);
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ namespace Elsa.Services
|
|||
|
||||
private readonly IWorkflowRegistry _workflowRegistry;
|
||||
private readonly IWorkflowFactory _workflowFactory;
|
||||
private readonly IWorkflowBuilder _workflowBuilder;
|
||||
private readonly Func<IWorkflowBuilder> _workflowBuilderFactory;
|
||||
private readonly IWorkflowContextManager _workflowContextManager;
|
||||
private readonly IMediator _mediator;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
|
@ -32,7 +32,7 @@ namespace Elsa.Services
|
|||
public WorkflowRunner(
|
||||
IWorkflowRegistry workflowRegistry,
|
||||
IWorkflowFactory workflowFactory,
|
||||
IWorkflowBuilder workflowBuilder,
|
||||
Func<IWorkflowBuilder> workflowBuilderFactory,
|
||||
IWorkflowContextManager workflowContextManager,
|
||||
IMediator mediator,
|
||||
IServiceProvider serviceProvider,
|
||||
|
|
@ -40,7 +40,7 @@ namespace Elsa.Services
|
|||
{
|
||||
_workflowRegistry = workflowRegistry;
|
||||
_workflowFactory = workflowFactory;
|
||||
_workflowBuilder = workflowBuilder;
|
||||
_workflowBuilderFactory = workflowBuilderFactory;
|
||||
_workflowContextManager = workflowContextManager;
|
||||
_mediator = mediator;
|
||||
_serviceProvider = serviceProvider;
|
||||
|
|
@ -71,7 +71,7 @@ namespace Elsa.Services
|
|||
string? contextId = default,
|
||||
CancellationToken cancellationToken = default)
|
||||
where T : IWorkflow =>
|
||||
await RunWorkflowAsync(_workflowBuilder.Build<T>(), activityId, input, correlationId, contextId, cancellationToken);
|
||||
await RunWorkflowAsync(_workflowBuilderFactory().Build<T>(), activityId, input, correlationId, contextId, cancellationToken);
|
||||
|
||||
public async ValueTask<WorkflowInstance> RunWorkflowAsync<T>(
|
||||
WorkflowInstance workflowInstance,
|
||||
|
|
@ -79,7 +79,7 @@ namespace Elsa.Services
|
|||
object? input = default,
|
||||
CancellationToken cancellationToken = default)
|
||||
where T : IWorkflow =>
|
||||
await RunWorkflowAsync(_workflowBuilder.Build<T>(), workflowInstance, activityId, input, cancellationToken);
|
||||
await RunWorkflowAsync(_workflowBuilderFactory().Build<T>(), workflowInstance, activityId, input, cancellationToken);
|
||||
|
||||
public async ValueTask<WorkflowInstance> RunWorkflowAsync(
|
||||
IWorkflow workflow,
|
||||
|
|
@ -89,7 +89,7 @@ namespace Elsa.Services
|
|||
string? contextId = default,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var workflowBlueprint = _workflowBuilder.Build(workflow);
|
||||
var workflowBlueprint = _workflowBuilderFactory().Build(workflow);
|
||||
return await RunWorkflowAsync(workflowBlueprint, activityId, input, correlationId, contextId, cancellationToken);
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ namespace Elsa.Services
|
|||
object? input = default,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var workflowBlueprint = _workflowBuilder.Build(workflow);
|
||||
var workflowBlueprint = _workflowBuilderFactory().Build(workflow);
|
||||
return await RunWorkflowAsync(workflowBlueprint, workflowInstance, activityId, input, cancellationToken);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -155,8 +155,7 @@ namespace Elsa.Triggers
|
|||
{
|
||||
var providers = _triggerProviders.ToList();
|
||||
var descriptors = new List<TriggerDescriptor>();
|
||||
var loadWorkflowContext = new LoadWorkflowContext(workflowBlueprint, workflowInstance);
|
||||
var workflowContext = await _workflowContextManager.LoadContext(loadWorkflowContext, cancellationToken);
|
||||
var workflowContext = workflowBlueprint.ContextOptions != null ? await _workflowContextManager.LoadContext(new LoadWorkflowContext(workflowBlueprint, workflowInstance), cancellationToken) : default;
|
||||
var workflowExecutionContext = new WorkflowExecutionContext(_serviceProvider, workflowBlueprint, workflowInstance, default, workflowContext);
|
||||
|
||||
foreach (var blockingActivity in blockingActivities)
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
using Elsa.DistributedLock;
|
||||
using Microsoft.Azure.Storage;
|
||||
using Microsoft.Azure.Storage.Blob;
|
||||
using Microsoft.Azure.Storage.RetryPolicies;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.DistributedLock;
|
||||
using Microsoft.Azure.Storage;
|
||||
using Microsoft.Azure.Storage.Blob;
|
||||
using Microsoft.Azure.Storage.RetryPolicies;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Elsa.DistributedLocking.AzureBlob
|
||||
namespace Elsa
|
||||
{
|
||||
// See also:
|
||||
// The lock duration can be 15 to 60 seconds, or can be infinite, Reference: https://docs.microsoft.com/en-us/rest/api/storageservices/lease-blob
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
|
||||
namespace Elsa.DistributedLocking.AzureBlob
|
||||
namespace Elsa
|
||||
{
|
||||
public static class ElsaOptionsExtensions
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Microsoft.Azure.Storage.Blob;
|
||||
|
||||
namespace Elsa.DistributedLocking.AzureBlob
|
||||
namespace Elsa
|
||||
{
|
||||
internal class LockedBlob
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using RedLockNet;
|
||||
using RedLockNet.SERedis;
|
||||
using RedLockNet.SERedis.Configuration;
|
||||
using StackExchange.Redis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Elsa.DistributedLocking.Redis
|
||||
namespace Elsa
|
||||
{
|
||||
public static class ElsaOptionsExtensions
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
using Elsa.DistributedLock;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using RedLockNet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.DistributedLock;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using RedLockNet;
|
||||
|
||||
namespace Elsa.DistributedLocking.Redis
|
||||
namespace Elsa
|
||||
{
|
||||
public class RedisLockProvider : IDistributedLockProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Elsa.DistributedLocking.SqlServer
|
||||
namespace Elsa
|
||||
{
|
||||
public static class ElsaOptionsExtensions
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
|||
using Elsa.DistributedLock;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Elsa.DistributedLocking.SqlServer
|
||||
namespace Elsa
|
||||
{
|
||||
// CREDITS:
|
||||
// Implementation taken & adapted from Workflow Core: https://github.com/danielgerlag/workflow-core/blob/master/src/providers/WorkflowCore.LockProviders.SqlServer/SqlLockProvider.cs
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
using Elsa.Activities.Console;
|
||||
using Elsa.Builders;
|
||||
using Elsa.Services;
|
||||
|
||||
namespace Elsa.Samples.CompositeActivitiesConsole.Activities
|
||||
{
|
||||
public class CountDownActivity : CompositeActivity
|
||||
{
|
||||
public override void Build(IWorkflowBuilder workflowBuilder)
|
||||
{
|
||||
workflowBuilder
|
||||
.WriteLine("3!")
|
||||
.WriteLine("2!")
|
||||
.WriteLine("1!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.9" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
using System.Data;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Samples.CompositeActivitiesConsole.Activities;
|
||||
using Elsa.Samples.CompositeActivitiesConsole.Workflows;
|
||||
using Elsa.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using YesSql.Provider.Sqlite;
|
||||
|
||||
namespace Elsa.Samples.CompositeActivitiesConsole
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
// Create a service container with Elsa services.
|
||||
var services = new ServiceCollection()
|
||||
.AddElsa(option => option.UsePersistence(db => db.UseSqLite("Data Source=elsa.db;Cache=Shared", IsolationLevel.ReadUncommitted)))
|
||||
.AddConsoleActivities()
|
||||
.AddActivity<CountDownActivity>()
|
||||
.AddWorkflow<CompositionWorkflow>()
|
||||
.BuildServiceProvider();
|
||||
|
||||
// Run startup actions (not needed when registering Elsa with a Host).
|
||||
var startupRunner = services.GetRequiredService<IStartupRunner>();
|
||||
await startupRunner.StartupAsync();
|
||||
|
||||
// Get a workflow host.
|
||||
var workflowRunner = services.GetService<IWorkflowRunner>();
|
||||
|
||||
// Execute the workflow.
|
||||
await workflowRunner.RunWorkflowAsync<CompositionWorkflow>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using Elsa.Activities.Console;
|
||||
using Elsa.Builders;
|
||||
using Elsa.Samples.CompositeActivitiesConsole.Activities;
|
||||
|
||||
namespace Elsa.Samples.CompositeActivitiesConsole.Workflows
|
||||
{
|
||||
/// <summary>
|
||||
/// A basic workflow with just one WriteLine activity.
|
||||
/// </summary>
|
||||
public class CompositionWorkflow : IWorkflow
|
||||
{
|
||||
public void Build(IWorkflowBuilder workflow) => workflow
|
||||
.WriteLine("Welcome to the Composite Activities demo workflow!")
|
||||
.Then<CountDownActivity>()
|
||||
.WriteLine("Done!");
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
using Microsoft.Extensions.Hosting;
|
||||
using NodaTime;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.DistributedLocking.Redis;
|
||||
using YesSql.Provider.Sqlite;
|
||||
|
||||
namespace Elsa.Samples.DistributedLock
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ using System.Threading.Tasks;
|
|||
using AutoFixture;
|
||||
using Elsa.Activities.Console;
|
||||
using Elsa.ComponentTests.Helpers;
|
||||
using Elsa.Core.IntegrationTests.Helpers;
|
||||
using Elsa.Models;
|
||||
using Elsa.Server.Api.Endpoints.WorkflowDefinitions;
|
||||
using Elsa.Testing.Shared.AutoFixture;
|
||||
using Elsa.Testing.Shared.Helpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Elsa.ComponentTests.Endpoints.WorkflowDefinitions
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Elsa.Core.IntegrationTests.Helpers
|
||||
namespace Elsa.Testing.Shared.Helpers
|
||||
{
|
||||
public class TemporaryFolder : IDisposable
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Builders;
|
||||
using Elsa.Core.IntegrationTests.Helpers;
|
||||
using Elsa.Services;
|
||||
using Elsa.Triggers;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Elsa.Core.IntegrationTests.Helpers
|
||||
namespace Elsa.Testing.Shared.Helpers
|
||||
{
|
||||
public class XunitConsoleForwarder : TextWriter
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue