Workflow Execution Log (#530)
* Rename provider folder to locking * Update project reference paths * Incremental work on workflow execution log storage * Fix deadlock * Add workflow execution log stores
This commit is contained in:
parent
ee89331b91
commit
8dbc3fe100
42
Elsa.sln
42
Elsa.sln
|
|
@ -63,12 +63,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{0A6747
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Testing.Shared", "test\shared\Elsa.Testing.Shared\Elsa.Testing.Shared.csproj", "{E7C689EB-5AD6-4E91-A007-6116EEA702FC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.DistributedLocking.SqlServer", "src\providers\Elsa.DistributedLocking.SqlServer\Elsa.DistributedLocking.SqlServer.csproj", "{150EF356-E8BC-4922-91C2-362017479409}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.DistributedLocking.Redis", "src\providers\Elsa.DistributedLocking.Redis\Elsa.DistributedLocking.Redis.csproj", "{EBD49CCA-5400-4C36-B5DF-7B28190AA323}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.DistributedLocking.AzureBlob", "src\providers\Elsa.DistributedLocking.AzureBlob\Elsa.DistributedLocking.AzureBlob.csproj", "{E20238CE-5C64-4F87-8753-3B4E1EC9A740}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "locking", "locking", "{7CD5C8D5-EC78-4A99-A514-F01CA7197AC8}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Core.IntegrationTests", "test\integration\Elsa.Core.IntegrationTests\Elsa.Core.IntegrationTests.csproj", "{4CB34AB3-01C9-4911-8914-EABAA744EAD3}"
|
||||
|
|
@ -177,6 +171,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Entity", "s
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.EntityChanged", "src\samples\console\Elsa.Samples.EntityChanged\Elsa.Samples.EntityChanged.csproj", "{A3149FE4-FD39-4DC2-AA9F-208C7216BC03}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.DistributedLocking.AzureBlob", "src\locking\Elsa.DistributedLocking.AzureBlob\Elsa.DistributedLocking.AzureBlob.csproj", "{C3842132-35BC-4F6D-85CC-7098887F4307}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.DistributedLocking.Redis", "src\locking\Elsa.DistributedLocking.Redis\Elsa.DistributedLocking.Redis.csproj", "{C90CD39C-8CDD-4BCB-AB6A-CF981D468DD2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.DistributedLocking.SqlServer", "src\locking\Elsa.DistributedLocking.SqlServer\Elsa.DistributedLocking.SqlServer.csproj", "{78F2A9DC-3092-4371-ABFE-87C5DA4DE351}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -239,18 +239,6 @@ Global
|
|||
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{150EF356-E8BC-4922-91C2-362017479409}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{150EF356-E8BC-4922-91C2-362017479409}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{150EF356-E8BC-4922-91C2-362017479409}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{150EF356-E8BC-4922-91C2-362017479409}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EBD49CCA-5400-4C36-B5DF-7B28190AA323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EBD49CCA-5400-4C36-B5DF-7B28190AA323}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EBD49CCA-5400-4C36-B5DF-7B28190AA323}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EBD49CCA-5400-4C36-B5DF-7B28190AA323}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E20238CE-5C64-4F87-8753-3B4E1EC9A740}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E20238CE-5C64-4F87-8753-3B4E1EC9A740}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E20238CE-5C64-4F87-8753-3B4E1EC9A740}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E20238CE-5C64-4F87-8753-3B4E1EC9A740}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4CB34AB3-01C9-4911-8914-EABAA744EAD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4CB34AB3-01C9-4911-8914-EABAA744EAD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4CB34AB3-01C9-4911-8914-EABAA744EAD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
|
@ -423,6 +411,18 @@ Global
|
|||
{A3149FE4-FD39-4DC2-AA9F-208C7216BC03}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A3149FE4-FD39-4DC2-AA9F-208C7216BC03}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A3149FE4-FD39-4DC2-AA9F-208C7216BC03}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C3842132-35BC-4F6D-85CC-7098887F4307}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C3842132-35BC-4F6D-85CC-7098887F4307}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C3842132-35BC-4F6D-85CC-7098887F4307}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C3842132-35BC-4F6D-85CC-7098887F4307}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C90CD39C-8CDD-4BCB-AB6A-CF981D468DD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C90CD39C-8CDD-4BCB-AB6A-CF981D468DD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C90CD39C-8CDD-4BCB-AB6A-CF981D468DD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C90CD39C-8CDD-4BCB-AB6A-CF981D468DD2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{78F2A9DC-3092-4371-ABFE-87C5DA4DE351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{78F2A9DC-3092-4371-ABFE-87C5DA4DE351}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{78F2A9DC-3092-4371-ABFE-87C5DA4DE351}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{78F2A9DC-3092-4371-ABFE-87C5DA4DE351}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -449,9 +449,6 @@ Global
|
|||
{0A3C36AB-2ACF-4175-A512-66B4C3DB9371} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
|
||||
{0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
|
||||
{E7C689EB-5AD6-4E91-A007-6116EEA702FC} = {0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D}
|
||||
{150EF356-E8BC-4922-91C2-362017479409} = {7CD5C8D5-EC78-4A99-A514-F01CA7197AC8}
|
||||
{EBD49CCA-5400-4C36-B5DF-7B28190AA323} = {7CD5C8D5-EC78-4A99-A514-F01CA7197AC8}
|
||||
{E20238CE-5C64-4F87-8753-3B4E1EC9A740} = {7CD5C8D5-EC78-4A99-A514-F01CA7197AC8}
|
||||
{7CD5C8D5-EC78-4A99-A514-F01CA7197AC8} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
|
||||
{4CB34AB3-01C9-4911-8914-EABAA744EAD3} = {0A3C36AB-2ACF-4175-A512-66B4C3DB9371}
|
||||
{FC47A50F-03B2-47D8-AAFB-075314FBA186} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
|
||||
|
|
@ -505,6 +502,9 @@ Global
|
|||
{0AA2A003-C79E-4B43-803E-E1150254D2B0} = {E02BD53A-5B08-47A0-920E-DD537A6AFAAA}
|
||||
{A0A8431F-3A2F-433A-BB0D-EB9627DFA739} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180}
|
||||
{A3149FE4-FD39-4DC2-AA9F-208C7216BC03} = {FC9F520F-BA51-4AD2-BFEE-EF787798E734}
|
||||
{C3842132-35BC-4F6D-85CC-7098887F4307} = {7CD5C8D5-EC78-4A99-A514-F01CA7197AC8}
|
||||
{C90CD39C-8CDD-4BCB-AB6A-CF981D468DD2} = {7CD5C8D5-EC78-4A99-A514-F01CA7197AC8}
|
||||
{78F2A9DC-3092-4371-ABFE-87C5DA4DE351} = {7CD5C8D5-EC78-4A99-A514-F01CA7197AC8}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158}
|
||||
|
|
|
|||
|
|
@ -25,11 +25,11 @@ namespace Elsa.Activities.AzureServiceBus.Services
|
|||
{
|
||||
await _semaphore.WaitAsync(cancellationToken);
|
||||
|
||||
if (_senders.TryGetValue(queueName, out var messageSender))
|
||||
return messageSender;
|
||||
|
||||
try
|
||||
{
|
||||
if (_senders.TryGetValue(queueName, out var messageSender))
|
||||
return messageSender;
|
||||
|
||||
await _managementClient.EnsureQueueExistsAsync(queueName, cancellationToken);
|
||||
var newMessageSender = new MessageSender(_connection, queueName);
|
||||
_senders.Add(queueName, newMessageSender);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ using Microsoft.Extensions.Logging;
|
|||
|
||||
namespace Elsa.Activities.AzureServiceBus.Services
|
||||
{
|
||||
public class QueueWorker
|
||||
public class QueueWorker : IAsyncDisposable
|
||||
{
|
||||
private readonly IMessageReceiver _messageReceiver;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
|
@ -63,5 +63,10 @@ namespace Elsa.Activities.AzureServiceBus.Services
|
|||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
await _messageReceiver.CloseAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,5 +4,6 @@
|
|||
{
|
||||
public static string WorkflowDefinitions = "WorkflowDefinitions";
|
||||
public static string WorkflowInstances = "WorkflowInstances";
|
||||
public static string WorkflowExecutionLog = "WorkflowExecutionLog";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
using NodaTime;
|
||||
|
||||
namespace Elsa.Models
|
||||
{
|
||||
public class ExecutionLogEntry
|
||||
{
|
||||
public ExecutionLogEntry()
|
||||
{
|
||||
}
|
||||
|
||||
public ExecutionLogEntry(string activityId, Instant timestamp)
|
||||
{
|
||||
ActivityId = activityId;
|
||||
Timestamp = timestamp;
|
||||
}
|
||||
|
||||
public string ActivityId { get; set; } = default!;
|
||||
public Instant Timestamp { get; set; }= default!;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using NodaTime;
|
||||
|
||||
namespace Elsa.Models
|
||||
{
|
||||
public class WorkflowExecutionLogRecord : Entity, ITenantScope
|
||||
{
|
||||
public WorkflowExecutionLogRecord()
|
||||
{
|
||||
}
|
||||
|
||||
public WorkflowExecutionLogRecord(string id, string? tenantId, string workflowInstanceId, string activityId, Instant timestamp, string? message, JObject? data = default)
|
||||
{
|
||||
Id = id;
|
||||
TenantId = tenantId;
|
||||
WorkflowInstanceId = workflowInstanceId;
|
||||
ActivityId = activityId;
|
||||
Timestamp = timestamp;
|
||||
Message = message;
|
||||
Data = data;
|
||||
}
|
||||
|
||||
public string? TenantId { get; }
|
||||
public string WorkflowInstanceId { get; set; } = default!;
|
||||
public string ActivityId { get; set; } = default!;
|
||||
public Instant Timestamp { get; set; }= default!;
|
||||
public string? Message { get; set; }
|
||||
public JObject? Data { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
using Elsa.Models;
|
||||
|
||||
namespace Elsa.Persistence
|
||||
{
|
||||
public interface IWorkflowExecutionLogStore : IStore<WorkflowExecutionLogRecord>
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -70,8 +70,7 @@ namespace Elsa.Services.Models
|
|||
}
|
||||
|
||||
public bool DeleteCompletedInstances => WorkflowBlueprint.DeleteCompletedInstances;
|
||||
//public ICollection<ExecutionLogEntry> ExecutionLog => WorkflowInstance.ExecutionLog;
|
||||
public ICollection<ExecutionLogEntry> ExecutionLog => new List<ExecutionLogEntry>();
|
||||
public ICollection<string> ExecutionLog => new List<string>();
|
||||
public WorkflowStatus Status => WorkflowInstance.WorkflowStatus;
|
||||
public bool HasBlockingActivities => WorkflowInstance.BlockingActivities.Any();
|
||||
public object? WorkflowContext { get; set; }
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace Elsa.ActivityResults
|
|||
if (previousEntry == null)
|
||||
return;
|
||||
|
||||
var activityId = previousEntry.ActivityId;
|
||||
var activityId = previousEntry;
|
||||
workflowExecutionContext.ScheduleActivity(activityId, _input);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ namespace Elsa
|
|||
|
||||
WorkflowDefinitionStoreFactory = sp => ActivatorUtilities.CreateInstance<InMemoryWorkflowDefinitionStore>(sp);
|
||||
WorkflowInstanceStoreFactory = sp => ActivatorUtilities.CreateInstance<InMemoryWorkflowInstanceStore>(sp);
|
||||
WorkflowExecutionLogStoreFactory = sp => ActivatorUtilities.CreateInstance<InMemoryWorkflowExecutionLogStore>(sp);
|
||||
StorageFactory = sp => Storage.Net.StorageFactory.Blobs.InMemory();
|
||||
DistributedLockProviderFactory = sp => new DefaultLockProvider();
|
||||
SignalFactory = sp => new Signal();
|
||||
|
|
@ -54,6 +55,7 @@ namespace Elsa
|
|||
internal Func<IServiceProvider, IBlobStorage> StorageFactory { get; set; }
|
||||
internal Func<IServiceProvider, IWorkflowDefinitionStore> WorkflowDefinitionStoreFactory { get; set; }
|
||||
internal Func<IServiceProvider, IWorkflowInstanceStore> WorkflowInstanceStoreFactory { get; set; }
|
||||
internal Func<IServiceProvider, IWorkflowExecutionLogStore> WorkflowExecutionLogStoreFactory { get; set; }
|
||||
internal Func<IServiceProvider, IDistributedLockProvider> DistributedLockProviderFactory { get; private set; }
|
||||
internal Func<IServiceProvider, ISignal> SignalFactory { get; private set; }
|
||||
internal Func<IServiceProvider, JsonSerializer> CreateJsonSerializer { get; private set; }
|
||||
|
|
@ -92,6 +94,12 @@ namespace Elsa
|
|||
WorkflowInstanceStoreFactory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ElsaOptions UseWorkflowExecutionLogStore(Func<IServiceProvider, IWorkflowExecutionLogStore> factory)
|
||||
{
|
||||
WorkflowExecutionLogStoreFactory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ElsaOptions UseAutoMapper(Action addAutoMapper)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
.AddSingleton(options)
|
||||
.AddScoped(options.WorkflowDefinitionStoreFactory)
|
||||
.AddScoped(options.WorkflowInstanceStoreFactory)
|
||||
.AddScoped(options.WorkflowExecutionLogStoreFactory)
|
||||
.AddSingleton(options.DistributedLockProviderFactory)
|
||||
.AddSingleton(options.SignalFactory)
|
||||
.AddSingleton(options.StorageFactory);
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Events;
|
||||
using Elsa.Models;
|
||||
using MediatR;
|
||||
using NodaTime;
|
||||
|
||||
namespace Elsa.Handlers
|
||||
{
|
||||
public class AppendExecutionLog : INotificationHandler<ActivityExecuted>
|
||||
{
|
||||
private readonly IClock _clock;
|
||||
public AppendExecutionLog(IClock clock) => _clock = clock;
|
||||
|
||||
public Task Handle(ActivityExecuted notification, CancellationToken cancellationToken)
|
||||
{
|
||||
notification.WorkflowExecutionContext.ExecutionLog.Add(new ExecutionLogEntry(notification.Activity.Id, _clock.GetCurrentInstant()));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ using System.Threading.Tasks;
|
|||
using Elsa.Events;
|
||||
using Elsa.Models;
|
||||
using Elsa.Persistence;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
|
|||
51
src/core/Elsa.Core/Handlers/WriteWorkflowExecutionLog.cs
Normal file
51
src/core/Elsa.Core/Handlers/WriteWorkflowExecutionLog.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Events;
|
||||
using Elsa.Models;
|
||||
using Elsa.Persistence;
|
||||
using Elsa.Services;
|
||||
using MediatR;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NodaTime;
|
||||
|
||||
namespace Elsa.Handlers
|
||||
{
|
||||
public class WriteWorkflowExecutionLog : INotificationHandler<ActivityExecuted>
|
||||
{
|
||||
private readonly IWorkflowExecutionLogStore _store;
|
||||
private readonly IIdGenerator _idGenerator;
|
||||
private readonly IClock _clock;
|
||||
private readonly JsonSerializer _jsonSerializer;
|
||||
|
||||
public WriteWorkflowExecutionLog(IWorkflowExecutionLogStore store, IIdGenerator idGenerator, IClock clock, JsonSerializer jsonSerializer)
|
||||
{
|
||||
_store = store;
|
||||
_idGenerator = idGenerator;
|
||||
_clock = clock;
|
||||
_jsonSerializer = jsonSerializer;
|
||||
}
|
||||
|
||||
public async Task Handle(ActivityExecuted notification, CancellationToken cancellationToken)
|
||||
{
|
||||
var workflowInstance = notification.WorkflowExecutionContext.WorkflowInstance;
|
||||
var id = _idGenerator.Generate();
|
||||
var tenantId = workflowInstance.TenantId;
|
||||
var workflowInstanceId = workflowInstance.Id;
|
||||
var activityId = notification.Activity.Id;
|
||||
var timeStamp = _clock.GetCurrentInstant();
|
||||
const string message = "Activity Executed";
|
||||
|
||||
var state = new
|
||||
{
|
||||
notification.ActivityExecutionContext.Output,
|
||||
notification.ActivityExecutionContext.Data
|
||||
};
|
||||
|
||||
var logData = JObject.FromObject(state, _jsonSerializer);
|
||||
var record = new WorkflowExecutionLogRecord(id, tenantId, workflowInstanceId, activityId, timeStamp, message, logData);
|
||||
|
||||
await _store.SaveAsync(record, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,3 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services;
|
||||
|
||||
|
|
@ -12,23 +8,5 @@ namespace Elsa.Persistence.InMemory
|
|||
public InMemoryWorkflowDefinitionStore(IIdGenerator idGenerator) : base(idGenerator)
|
||||
{
|
||||
}
|
||||
|
||||
public Task<int> CountAsync(VersionOptions? version = null, CancellationToken cancellationToken = default) => Task.FromResult(Entities.Values.WithVersion(version).Count());
|
||||
|
||||
public Task<WorkflowDefinition> GetAsync(string workflowDefinitionId, VersionOptions version, CancellationToken cancellationToken = default) =>
|
||||
Task.FromResult(Entities.Values.WithVersion(version).FirstOrDefault(x => x.Id == workflowDefinitionId));
|
||||
|
||||
public Task<WorkflowDefinition> GetByVersionIdAsync(string workflowDefinitionVersionId, CancellationToken cancellationToken = default) =>
|
||||
Task.FromResult(Entities.Values.FirstOrDefault(x => x.DefinitionVersionId == workflowDefinitionVersionId));
|
||||
|
||||
public Task<IEnumerable<WorkflowDefinition>> ListAsync(int? skip = null, int? take = null, VersionOptions? version = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = Entities.Values.WithVersion();
|
||||
|
||||
if (skip.HasValue) query = query.Skip(skip.Value);
|
||||
if (take.HasValue) query = query.Take(take.Value);
|
||||
|
||||
return Task.FromResult(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using Elsa.Models;
|
||||
using Elsa.Services;
|
||||
|
||||
namespace Elsa.Persistence.InMemory
|
||||
{
|
||||
public class InMemoryWorkflowExecutionLogStore : InMemoryStore<WorkflowExecutionLogRecord>, IWorkflowExecutionLogStore
|
||||
{
|
||||
public InMemoryWorkflowExecutionLogStore(IIdGenerator idGenerator) : base(idGenerator)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,3 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services;
|
||||
|
||||
|
|
@ -12,30 +8,5 @@ namespace Elsa.Persistence.InMemory
|
|||
public InMemoryWorkflowInstanceStore(IIdGenerator idGenerator) : base(idGenerator)
|
||||
{
|
||||
}
|
||||
|
||||
public Task<WorkflowInstance?> GetByCorrelationIdAsync(string correlationId, WorkflowStatus status, CancellationToken cancellationToken = default) =>
|
||||
Task.FromResult(Entities.Values.FirstOrDefault(instance => instance.CorrelationId == correlationId && instance.WorkflowStatus == status))!;
|
||||
|
||||
public Task<WorkflowInstance?> GetByIdAsync(string workflowInstanceId, CancellationToken cancellationToken = default) =>
|
||||
Task.FromResult(Entities.Values
|
||||
.FirstOrDefault(instance => instance.Id == workflowInstanceId))!;
|
||||
|
||||
public Task<IEnumerable<WorkflowInstance>> ListAsync(int page, int pageSize, CancellationToken cancellationToken = default) => Task.FromResult(Entities.Values.Skip(page * pageSize).Take(pageSize));
|
||||
|
||||
public Task<IEnumerable<WorkflowInstance>> ListByBlockingActivityTypeAsync(string activityType, CancellationToken cancellationToken = default) =>
|
||||
Task.FromResult(Entities.Values
|
||||
.Where(instance => instance.BlockingActivities.Any(a => a.ActivityType == activityType)));
|
||||
|
||||
public Task<IEnumerable<WorkflowInstance>> ListByCorrelationIdAsync(string correlationId, WorkflowStatus status, CancellationToken cancellationToken = default) =>
|
||||
Task.FromResult(Entities.Values.Where(instance => instance.CorrelationId == correlationId && instance.WorkflowStatus == status));
|
||||
|
||||
public Task<IEnumerable<WorkflowInstance>> ListByDefinitionAndStatusAsync(string workflowDefinitionId, string tenantId, WorkflowStatus workflowStatus, CancellationToken cancellationToken = default) =>
|
||||
Task.FromResult(Entities.Values
|
||||
.Where(instance => instance.DefinitionId == workflowDefinitionId && instance.WorkflowStatus == workflowStatus && instance.TenantId == tenantId));
|
||||
|
||||
public Task<IEnumerable<WorkflowInstance>> ListByDefinitionAsync(string workflowDefinitionId, string tenantId, CancellationToken cancellationToken = default) =>
|
||||
Task.FromResult(Entities.Values.Where(x => x.DefinitionId == workflowDefinitionId && x.TenantId == tenantId));
|
||||
|
||||
public Task<IEnumerable<WorkflowInstance>> ListByStatusAsync(WorkflowStatus workflowStatus, CancellationToken cancellationToken = default) => Task.FromResult(Entities.Values.Where(instance => instance.WorkflowStatus == workflowStatus));
|
||||
}
|
||||
}
|
||||
|
|
@ -259,6 +259,7 @@ namespace Elsa.Services
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
workflowExecutionContext.Fault(null, new LocalizedString(e.Message, e.Message));
|
||||
}
|
||||
}
|
||||
|
|
@ -279,6 +280,7 @@ namespace Elsa.Services
|
|||
await _mediator.Publish(new ActivityExecuting(activityExecutionContext), cancellationToken);
|
||||
await result.ExecuteAsync(activityExecutionContext, cancellationToken);
|
||||
workflowExecutionContext.WorkflowInstance.Output = activityExecutionContext.Output;
|
||||
workflowExecutionContext.ExecutionLog.Add(activity.Id);
|
||||
await _mediator.Publish(new ActivityExecuted(activityExecutionContext), cancellationToken);
|
||||
|
||||
activityOperation = Execute;
|
||||
|
|
|
|||
|
|
@ -32,14 +32,17 @@ namespace Elsa.Persistence.MongoDb.Extensions
|
|||
elsa.Services
|
||||
.AddSingleton<MongoDbWorkflowDefinitionStore>()
|
||||
.AddSingleton<MongoDbWorkflowInstanceStore>()
|
||||
.AddSingleton<MongoDbWorkflowExecutionLogStore>()
|
||||
.AddSingleton<ElsaMongoDbClient>()
|
||||
.AddSingleton(sp => sp.GetRequiredService<ElsaMongoDbClient>().WorkflowDefinitions)
|
||||
.AddSingleton(sp => sp.GetRequiredService<ElsaMongoDbClient>().WorkflowInstances)
|
||||
.AddSingleton(sp => sp.GetRequiredService<ElsaMongoDbClient>().WorkflowExecutionLog)
|
||||
.AddStartupTask<DatabaseInitializer>();
|
||||
|
||||
elsa
|
||||
.UseWorkflowDefinitionStore(sp => sp.GetRequiredService<MongoDbWorkflowDefinitionStore>())
|
||||
.UseWorkflowInstanceStore(sp => sp.GetRequiredService<MongoDbWorkflowInstanceStore>());
|
||||
.UseWorkflowInstanceStore(sp => sp.GetRequiredService<MongoDbWorkflowInstanceStore>())
|
||||
.UseWorkflowExecutionLogStore(sp => sp.GetRequiredService<MongoDbWorkflowExecutionLogStore>());
|
||||
|
||||
DatabaseRegister.RegisterMapsAndSerializers();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ namespace Elsa.Persistence.MongoDb.Services
|
|||
{
|
||||
await CreateWorkflowInstancesIndexes(cancellationToken);
|
||||
await CreateWorkflowDefinitionsIndexes(cancellationToken);
|
||||
await CreateWorkflowExecutionLogIndexes(cancellationToken);
|
||||
}
|
||||
|
||||
private async Task CreateWorkflowInstancesIndexes(CancellationToken cancellationToken)
|
||||
|
|
@ -40,6 +41,15 @@ namespace Elsa.Persistence.MongoDb.Services
|
|||
|
||||
await CreateIndexesAsync(_mongoClient.WorkflowDefinitions, cancellationToken, tenantKeysDefinition, definitionVersionIdKeysDefinition, versionKeysDefinition, nameKeysDefinition);
|
||||
}
|
||||
|
||||
private async Task CreateWorkflowExecutionLogIndexes(CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantKeysDefinition = Builders<WorkflowExecutionLogRecord>.IndexKeys.Ascending(x => x.TenantId);
|
||||
var workflowInstanceIdKeysDefinition = Builders<WorkflowExecutionLogRecord>.IndexKeys.Ascending(x => x.WorkflowInstanceId);
|
||||
var timestampKeysDefinition = Builders<WorkflowExecutionLogRecord>.IndexKeys.Ascending(x => x.Timestamp);
|
||||
|
||||
await CreateIndexesAsync(_mongoClient.WorkflowExecutionLog, cancellationToken, tenantKeysDefinition, workflowInstanceIdKeysDefinition, timestampKeysDefinition);
|
||||
}
|
||||
|
||||
private async Task CreateIndexesAsync<T>(IMongoCollection<T> collection, CancellationToken cancellationToken, params IndexKeysDefinition<T>[] definitions)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,5 +18,6 @@ namespace Elsa.Persistence.MongoDb.Services
|
|||
|
||||
public IMongoCollection<WorkflowDefinition> WorkflowDefinitions => _mongoDatabase.GetCollection<WorkflowDefinition>(CollectionNames.WorkflowDefinitions);
|
||||
public IMongoCollection<WorkflowInstance> WorkflowInstances => _mongoDatabase.GetCollection<WorkflowInstance>(CollectionNames.WorkflowInstances);
|
||||
public IMongoCollection<WorkflowExecutionLogRecord> WorkflowExecutionLog => _mongoDatabase.GetCollection<WorkflowExecutionLogRecord>(CollectionNames.WorkflowExecutionLog);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
using Elsa.Models;
|
||||
using Elsa.Services;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Elsa.Persistence.MongoDb.Stores
|
||||
{
|
||||
public class MongoDbWorkflowExecutionLogStore : MongoDbStore<WorkflowExecutionLogRecord>, IWorkflowExecutionLogStore
|
||||
{
|
||||
public MongoDbWorkflowExecutionLogStore(IMongoCollection<WorkflowExecutionLogRecord> collection, IIdGenerator idGenerator) : base(collection, idGenerator)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ namespace Elsa.Persistence.YesSql.Documents
|
|||
public class WorkflowDefinitionDocument : YesSqlDocument
|
||||
{
|
||||
public string DefinitionId { get; set; } = default!;
|
||||
|
||||
public string DefinitionVersionId { get; set; } = default!;
|
||||
public string? TenantId { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using NodaTime;
|
||||
|
||||
namespace Elsa.Persistence.YesSql.Documents
|
||||
{
|
||||
public class WorkflowExecutionLogRecordDocument : YesSqlDocument
|
||||
{
|
||||
public string RecordId { get; } = default!;
|
||||
public string? TenantId { get; }
|
||||
public string WorkflowInstanceId { get; set; } = default!;
|
||||
public string ActivityId { get; set; } = default!;
|
||||
public Instant Timestamp { get; set; }= default!;
|
||||
public string? Message { get; set; }
|
||||
public JObject? Data { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ namespace Elsa.Persistence.YesSql.Documents
|
|||
set => _blockingActivities = new HashSet<BlockingActivity>(value, BlockingActivityEqualityComparer.Instance);
|
||||
}
|
||||
|
||||
public ICollection<ExecutionLogEntry> ExecutionLog { get; set; } = new List<ExecutionLogEntry>();
|
||||
public ICollection<WorkflowExecutionLogRecord> ExecutionLog { get; set; } = new List<WorkflowExecutionLogRecord>();
|
||||
public WorkflowFault? Fault { get; set; }
|
||||
public Stack<ScheduledActivity> ScheduledActivities { get; set; } = new();
|
||||
public Stack<ScheduledActivity> PostScheduledActivities { get; set; } = new();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using System.Data;
|
|||
using System.Linq;
|
||||
using Elsa.Data;
|
||||
using Elsa.Persistence.YesSql.Data;
|
||||
using Elsa.Persistence.YesSql.Documents;
|
||||
using Elsa.Persistence.YesSql.Indexes;
|
||||
using Elsa.Persistence.YesSql.Mapping;
|
||||
using Elsa.Persistence.YesSql.Services;
|
||||
|
|
@ -11,7 +10,6 @@ using Elsa.Persistence.YesSql.Stores;
|
|||
using Elsa.Runtime;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using YesSql;
|
||||
using YesSql.Data;
|
||||
using YesSql.Indexes;
|
||||
using YesSql.Provider.Sqlite;
|
||||
|
||||
|
|
@ -27,6 +25,7 @@ namespace Elsa.Persistence.YesSql.Extensions
|
|||
elsa.Services
|
||||
.AddScoped<YesSqlWorkflowDefinitionStore>()
|
||||
.AddScoped<YesSqlWorkflowInstanceStore>()
|
||||
.AddScoped<YesSqlWorkflowExecutionLogStore>()
|
||||
.AddSingleton(sp => CreateStore(sp, configure))
|
||||
.AddScoped(CreateSession)
|
||||
.AddScoped<IDataMigrationManager, DataMigrationManager>()
|
||||
|
|
@ -35,11 +34,13 @@ namespace Elsa.Persistence.YesSql.Extensions
|
|||
.AddDataMigration<Migrations>()
|
||||
.AddAutoMapperProfile<AutoMapperProfile>()
|
||||
.AddIndexProvider<WorkflowDefinitionIndexProvider>()
|
||||
.AddIndexProvider<WorkflowInstanceIndexProvider>();
|
||||
.AddIndexProvider<WorkflowInstanceIndexProvider>()
|
||||
.AddIndexProvider<WorkflowExecutionLogRecordIndexProvider>();
|
||||
|
||||
return elsa
|
||||
.UseWorkflowDefinitionStore(sp => sp.GetRequiredService<YesSqlWorkflowDefinitionStore>())
|
||||
.UseWorkflowInstanceStore(sp => sp.GetRequiredService<YesSqlWorkflowInstanceStore>());
|
||||
.UseWorkflowInstanceStore(sp => sp.GetRequiredService<YesSqlWorkflowInstanceStore>())
|
||||
.UseWorkflowExecutionLogStore(sp => sp.GetRequiredService<YesSqlWorkflowExecutionLogStore>());
|
||||
}
|
||||
|
||||
public static IServiceCollection AddIndexProvider<T>(this IServiceCollection services) where T : class, IIndexProvider => services.AddSingleton<IIndexProvider, T>();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Elsa.Data;
|
||||
using Elsa.Models;
|
||||
using Elsa.Persistence.YesSql.Documents;
|
||||
using YesSql.Indexes;
|
||||
|
||||
|
|
@ -8,7 +7,7 @@ namespace Elsa.Persistence.YesSql.Indexes
|
|||
public class WorkflowDefinitionIndex : MapIndex
|
||||
{
|
||||
public string? TenantId { get; set; }
|
||||
public string EntityId { get; set; } = default!;
|
||||
public string DefinitionId { get; set; } = default!;
|
||||
public string DefinitionVersionId { get; set; } = default!;
|
||||
public int Version { get; set; }
|
||||
public bool IsLatest { get; set; }
|
||||
|
|
@ -26,7 +25,7 @@ namespace Elsa.Persistence.YesSql.Indexes
|
|||
.Map(
|
||||
workflowDefinition => new WorkflowDefinitionIndex
|
||||
{
|
||||
EntityId = workflowDefinition.DefinitionId,
|
||||
DefinitionId = workflowDefinition.DefinitionId,
|
||||
TenantId = workflowDefinition.TenantId,
|
||||
DefinitionVersionId = workflowDefinition.DefinitionVersionId,
|
||||
Version = workflowDefinition.Version,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using Elsa.Data;
|
||||
using Elsa.Persistence.YesSql.Documents;
|
||||
using YesSql.Indexes;
|
||||
|
||||
namespace Elsa.Persistence.YesSql.Indexes
|
||||
{
|
||||
public class WorkflowExecutionLogRecordIndex : MapIndex
|
||||
{
|
||||
public string? TenantId { get; set; }
|
||||
public string RecordId { get; set; } = default!;
|
||||
public string WorkflowInstanceId { get; set; } = default!;
|
||||
public DateTime Timestamp { get; set; }
|
||||
}
|
||||
|
||||
public class WorkflowExecutionLogRecordIndexProvider : IndexProvider<WorkflowExecutionLogRecordDocument>
|
||||
{
|
||||
public WorkflowExecutionLogRecordIndexProvider() => CollectionName = CollectionNames.WorkflowExecutionLog;
|
||||
|
||||
public override void Describe(DescribeContext<WorkflowExecutionLogRecordDocument> context)
|
||||
{
|
||||
context.For<WorkflowExecutionLogRecordIndex>()
|
||||
.Map(
|
||||
record => new WorkflowExecutionLogRecordIndex
|
||||
{
|
||||
RecordId = record.RecordId,
|
||||
TenantId = record.TenantId,
|
||||
WorkflowInstanceId = record.WorkflowInstanceId,
|
||||
Timestamp = record.Timestamp.ToDateTimeUtc()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,12 @@ namespace Elsa.Persistence.YesSql.Mapping
|
|||
.ForMember(d => d.Id, d => d.Ignore())
|
||||
.ReverseMap()
|
||||
.ForMember(d => d.Id, d => d.MapFrom(s => s.DefinitionId));
|
||||
|
||||
CreateMap<WorkflowExecutionLogRecord, WorkflowExecutionLogRecordDocument>()
|
||||
.ForMember(d => d.RecordId, d => d.MapFrom(s => s.Id))
|
||||
.ForMember(d => d.Id, d => d.Ignore())
|
||||
.ReverseMap()
|
||||
.ForMember(d => d.Id, d => d.MapFrom(s => s.RecordId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ namespace Elsa.Persistence.YesSql
|
|||
SchemaBuilder.CreateMapIndexTable<WorkflowDefinitionIndex>(
|
||||
table => table
|
||||
.Column<string?>(nameof(WorkflowDefinitionIndex.TenantId))
|
||||
.Column<string>(nameof(WorkflowDefinitionIndex.EntityId))
|
||||
.Column<string>(nameof(WorkflowDefinitionIndex.DefinitionId))
|
||||
.Column<string>(nameof(WorkflowDefinitionIndex.DefinitionVersionId))
|
||||
.Column<int>(nameof(WorkflowDefinitionIndex.Version))
|
||||
.Column<bool>(nameof(WorkflowDefinitionIndex.IsLatest))
|
||||
|
|
@ -40,13 +40,21 @@ namespace Elsa.Persistence.YesSql
|
|||
|
||||
SchemaBuilder.CreateMapIndexTable<WorkflowInstanceBlockingActivitiesIndex>(
|
||||
table => table
|
||||
.Column<string?>("TenantId")
|
||||
.Column<string>("ActivityId")
|
||||
.Column<string>("ActivityType")
|
||||
.Column<string?>("CorrelationId")
|
||||
.Column("WorkflowStatus", DbType.String)
|
||||
.Column("CreatedAt", DbType.DateTimeOffset),
|
||||
.Column<string?>(nameof(WorkflowInstanceBlockingActivitiesIndex.TenantId))
|
||||
.Column<string>(nameof(WorkflowInstanceBlockingActivitiesIndex.ActivityId))
|
||||
.Column<string>(nameof(WorkflowInstanceBlockingActivitiesIndex.ActivityType))
|
||||
.Column<string?>(nameof(WorkflowInstanceBlockingActivitiesIndex.CorrelationId))
|
||||
.Column(nameof(WorkflowInstanceBlockingActivitiesIndex.WorkflowStatus), DbType.String)
|
||||
.Column(nameof(WorkflowInstanceBlockingActivitiesIndex.CreatedAt), DbType.DateTimeOffset),
|
||||
CollectionNames.WorkflowInstances);
|
||||
|
||||
SchemaBuilder.CreateMapIndexTable<WorkflowExecutionLogRecordIndex>(
|
||||
table => table
|
||||
.Column<string?>(nameof(WorkflowExecutionLogRecordIndex.RecordId))
|
||||
.Column<string?>(nameof(WorkflowExecutionLogRecordIndex.TenantId))
|
||||
.Column<string>(nameof(WorkflowExecutionLogRecordIndex.WorkflowInstanceId))
|
||||
.Column(nameof(WorkflowExecutionLogRecordIndex.Timestamp), DbType.DateTimeOffset),
|
||||
CollectionNames.WorkflowExecutionLog);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Elsa.Data;
|
||||
using Elsa.Services;
|
||||
|
||||
using YesSql;
|
||||
|
||||
namespace Elsa.Persistence.YesSql.Services
|
||||
|
|
@ -21,6 +19,7 @@ namespace Elsa.Persistence.YesSql.Services
|
|||
{
|
||||
await _store.InitializeCollectionAsync(CollectionNames.WorkflowDefinitions);
|
||||
await _store.InitializeCollectionAsync(CollectionNames.WorkflowInstances);
|
||||
await _store.InitializeCollectionAsync(CollectionNames.WorkflowExecutionLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ namespace Elsa.Persistence.YesSql.Stores
|
|||
{
|
||||
public abstract class YesSqlStore<T, TDocument> : IStore<T> where T : class, IEntity where TDocument : class
|
||||
{
|
||||
private readonly SemaphoreSlim _semaphore = new(1);
|
||||
|
||||
public YesSqlStore(ISession session, IIdGenerator idGenerator, IMapper mapper, string collectionName)
|
||||
{
|
||||
IdGenerator = idGenerator;
|
||||
|
|
@ -31,10 +33,19 @@ namespace Elsa.Persistence.YesSql.Stores
|
|||
|
||||
public async Task SaveAsync(T entity, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var existingDocument = await FindDocumentAsync(entity, cancellationToken);
|
||||
var document = Mapper.Map(entity, existingDocument);
|
||||
Session.Save(document, CollectionName);
|
||||
await Session.CommitAsync();
|
||||
await _semaphore.WaitAsync(cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
var existingDocument = await FindDocumentAsync(entity, cancellationToken);
|
||||
var document = Mapper.Map(entity, existingDocument);
|
||||
Session.Save(document, CollectionName);
|
||||
await Session.CommitAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_semaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(T entity, CancellationToken cancellationToken = default)
|
||||
|
|
@ -68,14 +79,14 @@ namespace Elsa.Persistence.YesSql.Stores
|
|||
var documents = await Query(specification, orderBy, paging, cancellationToken).ListAsync();
|
||||
return Map(documents);
|
||||
}
|
||||
|
||||
|
||||
protected virtual IQuery<TDocument> Query(ISpecification<T> specification, IOrderBy<T>? orderBy = default, IPaging? paging = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = ToQuery(specification);
|
||||
|
||||
if (orderBy != null)
|
||||
if (orderBy != null)
|
||||
query = OrderBy(query, orderBy, specification);
|
||||
|
||||
|
||||
if (paging != null)
|
||||
query = query.Skip(paging.Skip).Take(paging.Take);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ namespace Elsa.Persistence.YesSql.Stores
|
|||
{
|
||||
}
|
||||
|
||||
protected override async Task<WorkflowDefinitionDocument?> FindDocumentAsync(WorkflowDefinition entity, CancellationToken cancellationToken) => await Query<WorkflowDefinitionIndex>(x => x.EntityId == entity.Id).FirstOrDefaultAsync();
|
||||
protected override async Task<WorkflowDefinitionDocument?> FindDocumentAsync(WorkflowDefinition entity, CancellationToken cancellationToken) => await Query<WorkflowDefinitionIndex>(x => x.DefinitionId == entity.Id).FirstOrDefaultAsync();
|
||||
|
||||
protected override IQuery<WorkflowDefinitionDocument> MapSpecification(ISpecification<WorkflowDefinition> specification)
|
||||
{
|
||||
if (specification is EntityIdSpecification<WorkflowDefinition> entityIdSpecification)
|
||||
return Query<WorkflowDefinitionIndex>(x => x.EntityId == entityIdSpecification.Id);
|
||||
return Query<WorkflowDefinitionIndex>(x => x.DefinitionId == entityIdSpecification.Id);
|
||||
|
||||
return AutoMapSpecification<WorkflowDefinitionIndex>(specification);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Elsa.Data;
|
||||
using Elsa.Models;
|
||||
using Elsa.Persistence.Specifications;
|
||||
using Elsa.Persistence.YesSql.Documents;
|
||||
using Elsa.Persistence.YesSql.Indexes;
|
||||
using YesSql;
|
||||
using IIdGenerator = Elsa.Services.IIdGenerator;
|
||||
|
||||
namespace Elsa.Persistence.YesSql.Stores
|
||||
{
|
||||
public class YesSqlWorkflowExecutionLogStore : YesSqlStore<WorkflowExecutionLogRecord, WorkflowExecutionLogRecordDocument>, IWorkflowExecutionLogStore
|
||||
{
|
||||
public YesSqlWorkflowExecutionLogStore(ISession session, IIdGenerator idGenerator, IMapper mapper) : base(session, idGenerator, mapper, CollectionNames.WorkflowExecutionLog)
|
||||
{
|
||||
}
|
||||
|
||||
protected override async Task<WorkflowExecutionLogRecordDocument?> FindDocumentAsync(WorkflowExecutionLogRecord entity, CancellationToken cancellationToken) => await Query<WorkflowExecutionLogRecordIndex>(x => x.RecordId == entity.Id).FirstOrDefaultAsync();
|
||||
protected override IQuery<WorkflowExecutionLogRecordDocument> MapSpecification(ISpecification<WorkflowExecutionLogRecord> specification) => AutoMapSpecification<WorkflowExecutionLogRecordIndex>(specification);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
|
||||
<xs:element name="Weavers">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
<xs:attribute name="VerifyAssembly" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="GenerateXsd" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
|
||||
<xs:element name="Weavers">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
<xs:attribute name="VerifyAssembly" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="GenerateXsd" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
|
||||
<xs:element name="Weavers">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
<xs:attribute name="VerifyAssembly" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="GenerateXsd" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
|
|
@ -6,11 +6,12 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\activities\Elsa.Activities.AzureServiceBus\Elsa.Activities.AzureServiceBus.csproj"/>
|
||||
<ProjectReference Include="..\..\..\core\Elsa\Elsa.csproj"/>
|
||||
<ProjectReference Include="..\..\..\activities\Elsa.Activities.AzureServiceBus\Elsa.Activities.AzureServiceBus.csproj" />
|
||||
<ProjectReference Include="..\..\..\core\Elsa\Elsa.csproj" />
|
||||
<ProjectReference Include="..\..\..\persistence\Elsa.Persistence.YesSql\Elsa.Persistence.YesSql.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Elsa.Activities.AzureServiceBus.Extensions;
|
||||
using Elsa.Persistence.InMemory;
|
||||
using Elsa.Persistence.YesSql.Extensions;
|
||||
using Elsa.Samples.AzureServiceBusWorker.Workflows;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -19,7 +20,7 @@ namespace Elsa.Samples.AzureServiceBusWorker
|
|||
.ConfigureServices((hostContext, services) =>
|
||||
{
|
||||
services
|
||||
.AddElsa()
|
||||
.AddElsa(options => options.UseYesSqlPersistence())
|
||||
.AddConsoleActivities()
|
||||
.AddTimerActivities()
|
||||
.AddAzureServiceBusActivities(options => options.ConnectionString = hostContext.Configuration.GetConnectionString("AzureServiceBus"))
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@
|
|||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"AzureServiceBus": ""
|
||||
"AzureServiceBus": "Endpoint=sb://elsa-samples.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=MAwkyEFjQdDFX4gI6jM/nvBMwHcEZQ4RHQ2XC6fFB9Q="
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\core\Elsa\Elsa.csproj"/>
|
||||
<ProjectReference Include="..\..\..\providers\Elsa.DistributedLocking.AzureBlob\Elsa.DistributedLocking.AzureBlob.csproj"/>
|
||||
<ProjectReference Include="..\..\..\activities\Elsa.Activities.Timers\Elsa.Activities.Timers.csproj"/>
|
||||
<ProjectReference Include="..\..\..\providers\Elsa.DistributedLocking.Redis\Elsa.DistributedLocking.Redis.csproj"/>
|
||||
<ProjectReference Include="..\..\..\providers\Elsa.DistributedLocking.SqlServer\Elsa.DistributedLocking.SqlServer.csproj"/>
|
||||
<ProjectReference Include="..\..\..\locking\Elsa.DistributedLocking.AzureBlob\Elsa.DistributedLocking.AzureBlob.csproj"/>
|
||||
<ProjectReference Include="..\..\..\locking\Elsa.DistributedLocking.Redis\Elsa.DistributedLocking.Redis.csproj"/>
|
||||
<ProjectReference Include="..\..\..\locking\Elsa.DistributedLocking.SqlServer\Elsa.DistributedLocking.SqlServer.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Elsa.Server.Api.Models
|
|||
{
|
||||
Variables = new Variables();
|
||||
Activities = new List<ActivityInstance>();
|
||||
ExecutionLog = new List<ExecutionLogEntry>();
|
||||
ExecutionLog = new List<WorkflowExecutionLogRecord>();
|
||||
ScheduledActivities = new Stack<ScheduledActivity>();
|
||||
PostScheduledActivities = new Stack<ScheduledActivity>();
|
||||
}
|
||||
|
|
@ -42,7 +42,7 @@ namespace Elsa.Server.Api.Models
|
|||
set => _blockingActivities = new HashSet<BlockingActivity>(value, BlockingActivityEqualityComparer.Instance);
|
||||
}
|
||||
|
||||
[DataMember(Order = 16)] public ICollection<ExecutionLogEntry> ExecutionLog { get; set; }
|
||||
[DataMember(Order = 16)] public ICollection<WorkflowExecutionLogRecord> ExecutionLog { get; set; }
|
||||
[DataMember(Order = 17)] public WorkflowFault? Fault { get; set; }
|
||||
[DataMember(Order = 18)] public Stack<ScheduledActivity> ScheduledActivities { get; set; }
|
||||
[DataMember(Order = 19)] public Stack<ScheduledActivity> PostScheduledActivities { get; set; }
|
||||
|
|
|
|||
Loading…
Reference in a new issue