Remove IWorkflowExecutionContextStore and related classes

Removed the IWorkflowExecutionContextStore interface and its implementations, along with the associated handlers and registrations. This change simplifies the codebase by eliminating unnecessary components and their dependencies.
This commit is contained in:
Sipke Schoorstra 2024-07-18 18:57:42 +02:00
parent 827680b3c4
commit 5586151bf1
24 changed files with 94 additions and 202 deletions

View file

@ -1,5 +1,6 @@
using Elsa.Features.Services;
using Elsa.Hangfire.Features;
using Elsa.Scheduling;
using Elsa.Scheduling.Features;
using Elsa.Workflows.Runtime.Features;
using JetBrains.Annotations;
@ -20,7 +21,7 @@ public static class ModuleExtensions
{
return module.Use(configure);
}
/// <summary>
/// Configures Hangfire to use SQL Server storage. Only use this feature if you are not configuring Hangfire yourself.
/// </summary>
@ -29,7 +30,7 @@ public static class ModuleExtensions
feature.Module.Use(configure);
return feature;
}
/// <summary>
/// Configures Hangfire to use SQLite storage. Only use this feature if you are not configuring Hangfire yourself.
/// </summary>
@ -38,7 +39,7 @@ public static class ModuleExtensions
feature.Module.Use(configure);
return feature;
}
/// <summary>
/// Installs a Hangfire implementation for <see cref="IWorkflowScheduler"/>.
/// </summary>
@ -47,7 +48,7 @@ public static class ModuleExtensions
feature.Module.Use(configure);
return feature;
}
/// <summary>
/// Installs a Hangfire implementation for <see cref="IWorkflowScheduler"/>.
/// </summary>

View file

@ -3,6 +3,7 @@ using Elsa.Features.Attributes;
using Elsa.Features.Services;
using Elsa.Hangfire.Handlers;
using Elsa.Hangfire.Services;
using Elsa.Scheduling;
using Elsa.Scheduling.Features;
using Elsa.Workflows.Contracts;
using Microsoft.Extensions.DependencyInjection;

View file

@ -1,5 +1,6 @@
using Elsa.Features.Services;
using Elsa.Quartz.Features;
using Elsa.Scheduling;
using Elsa.Scheduling.Features;
// ReSharper disable once CheckNamespace
@ -17,7 +18,7 @@ public static class ModuleExtensions
{
return module.Use(configure);
}
/// <summary>
/// Installs a Quartz.NET implementation for <see cref="IWorkflowScheduler"/>.
/// </summary>

View file

@ -4,6 +4,7 @@ using Elsa.Features.Services;
using Elsa.Quartz.Handlers;
using Elsa.Quartz.Jobs;
using Elsa.Quartz.Services;
using Elsa.Scheduling;
using Elsa.Scheduling.Features;
using Elsa.Workflows.Contracts;
using Microsoft.Extensions.DependencyInjection;

View file

@ -1,6 +1,6 @@
using Elsa.Abstractions;
using Elsa.Extensions;
using Elsa.Workflows.Management.Contracts;
using Elsa.Workflows.Management;
using JetBrains.Annotations;
namespace Elsa.Workflows.Api.Endpoints.WorkflowInstances.ExecutionState;

View file

@ -1,4 +1,5 @@
using Elsa.Workflows.Management;
using Elsa.Workflows.Management.Entities;
namespace Elsa.Workflows.Runtime;

View file

@ -1,24 +0,0 @@
namespace Elsa.Workflows.Runtime;
/// <summary>
/// Stores <see cref="WorkflowExecutionContext"/> records.
/// </summary>
public interface IWorkflowExecutionContextStore
{
/// <summary>
/// Saves a record of the <see cref="WorkflowExecutionContext"/>.
/// </summary>
/// <param name="context">The <see cref="WorkflowExecutionContext"/> to save.</param>
Task SaveAsync(WorkflowExecutionContext context);
/// <summary>
/// Finds a <see cref="WorkflowExecutionContext"/> with the specified ID.
/// </summary>
/// <returns>The matching entity or null if no match was found.</returns>
Task<WorkflowExecutionContext?> FindAsync(string workflowExecutionContextId);
/// <summary>
/// Deletes the record of the <see cref="WorkflowExecutionContext"/> with the specified ID if it exists.
/// </summary>
Task DeleteAsync(string workflowExecutionContextId);
}

View file

@ -18,6 +18,7 @@ using Elsa.Workflows.Runtime.Handlers;
using Elsa.Workflows.Runtime.HostedServices;
using Elsa.Workflows.Runtime.Options;
using Elsa.Workflows.Runtime.Providers;
using Elsa.Workflows.Runtime.Services;
using Elsa.Workflows.Runtime.Stores;
using Medallion.Threading;
using Medallion.Threading.FileSystem;
@ -67,9 +68,6 @@ public class WorkflowRuntimeFeature : FeatureBase
/// A factory that instantiates an <see cref="IActivityExecutionStore"/>.
public Func<IServiceProvider, IActivityExecutionStore> ActivityExecutionLogStore { get; set; } = sp => sp.GetRequiredService<MemoryActivityExecutionStore>();
/// A factory that instantiates an <see cref="IWorkflowExecutionContextStore"/>.
public Func<IServiceProvider, IWorkflowExecutionContextStore> WorkflowExecutionContextStore { get; set; } = sp => sp.GetRequiredService<MemoryWorkflowExecutionContextStore>();
/// A factory that instantiates an <see cref="IDistributedLockProvider"/>.
public Func<IServiceProvider, IDistributedLockProvider> DistributedLockProvider { get; set; } = _ => new FileDistributedSynchronizationProvider(new DirectoryInfo(Path.Combine(Environment.CurrentDirectory, "App_Data/locks")));
@ -174,7 +172,6 @@ public class WorkflowRuntimeFeature : FeatureBase
.AddScoped(WorkflowRuntime)
.AddScoped(WorkflowDispatcher)
.AddScoped(WorkflowCancellationDispatcher)
.AddScoped(WorkflowExecutionContextStore)
.AddScoped(RunTaskDispatcher)
.AddScoped(WorkflowExecutionLogSink)
.AddSingleton(BackgroundActivityScheduler)
@ -235,7 +232,6 @@ public class WorkflowRuntimeFeature : FeatureBase
.AddMemoryStore<BookmarkQueueItem, MemoryBookmarkQueueStore>()
.AddMemoryStore<WorkflowExecutionLogRecord, MemoryWorkflowExecutionLogStore>()
.AddMemoryStore<ActivityExecutionRecord, MemoryActivityExecutionStore>()
.AddMemoryStore<WorkflowExecutionContext, MemoryWorkflowExecutionContextStore>()
// Distributed locking.
.AddSingleton(DistributedLockProvider)
@ -253,7 +249,6 @@ public class WorkflowRuntimeFeature : FeatureBase
.AddNotificationHandler<DeleteTriggers>()
.AddNotificationHandler<DeleteActivityExecutionLogRecords>()
.AddNotificationHandler<DeleteWorkflowExecutionLogRecords>()
.AddNotificationHandler<WorkflowExecutionContextNotificationsHandler>()
.AddNotificationHandler<RefreshActivityRegistry>()
.AddNotificationHandler<SignalBookmarkQueueWorker>()

View file

@ -1,6 +1,5 @@
using Elsa.Extensions;
using Elsa.Mediator.Contracts;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Runtime.Middleware.Activities;
using Elsa.Workflows.Runtime.Notifications;
using Elsa.Workflows.Runtime.Stimuli;

View file

@ -1,5 +1,5 @@
using Elsa.Mediator.Contracts;
using Elsa.Workflows.Management.Contracts;
using Elsa.Workflows.Management;
using Elsa.Workflows.Runtime.Notifications;
using JetBrains.Annotations;

View file

@ -2,7 +2,6 @@ using Elsa.Mediator.Contracts;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Management.Activities.WorkflowDefinitionActivity;
using Elsa.Workflows.Management.Contracts;
using Elsa.Workflows.Management.Entities;
using Elsa.Workflows.Runtime.Notifications;
using JetBrains.Annotations;
@ -15,7 +14,7 @@ public class RefreshActivityRegistry(IWorkflowDefinitionActivityRegistryUpdater
/// <inheritdoc />
public async Task HandleAsync(WorkflowDefinitionsReloaded notification, CancellationToken cancellationToken)
{
foreach (var reloadedWorkflowDefinition in notification.ReloadedWorkflowDefinitions)
foreach (var reloadedWorkflowDefinition in notification.ReloadedWorkflowDefinitions)
await UpdateDefinition(reloadedWorkflowDefinition.DefinitionVersionId, reloadedWorkflowDefinition.UsableAsActivity);
}

View file

@ -1,35 +0,0 @@
using Elsa.Mediator.Contracts;
using Elsa.Workflows.Management.Notifications;
using Elsa.Workflows.Notifications;
namespace Elsa.Workflows.Runtime.Handlers;
/// <summary>
/// Deletes workflow execution log records in response to the <see cref="WorkflowInstancesDeleting"/> notification.
/// </summary>
internal class WorkflowExecutionContextNotificationsHandler :
INotificationHandler<WorkflowExecuting>,
INotificationHandler<WorkflowExecuted>
{
private readonly IWorkflowExecutionContextStore _store;
/// <summary>
/// Initializes a new instance of the <see cref="DeleteWorkflowExecutionLogRecords"/> class.
/// </summary>
public WorkflowExecutionContextNotificationsHandler(IWorkflowExecutionContextStore store)
{
_store = store;
}
/// <inheritdoc />
public Task HandleAsync(WorkflowExecuting notification, CancellationToken cancellationToken)
{
return _store.SaveAsync(notification.WorkflowExecutionContext);
}
/// <inheritdoc />
public Task HandleAsync(WorkflowExecuted notification, CancellationToken cancellationToken)
{
return _store.DeleteAsync(notification.WorkflowExecutionContext.Id);
}
}

View file

@ -1,41 +0,0 @@
using Elsa.Common.Services;
using Elsa.Workflows.Runtime.Stores;
namespace Elsa.Workflows.Runtime;
/// <summary>
/// Stores <see cref="WorkflowExecutionContext"/> in memory.
/// </summary>
public class MemoryWorkflowExecutionContextStore : IWorkflowExecutionContextStore
{
private readonly MemoryStore<WorkflowExecutionContext> _store;
/// <summary>
/// Initializes a new instance of the <see cref="MemoryActivityExecutionStore"/> class.
/// </summary>
public MemoryWorkflowExecutionContextStore(MemoryStore<WorkflowExecutionContext> store)
{
_store = store;
}
/// <inheritdoc />
public Task SaveAsync(WorkflowExecutionContext context)
{
_store.Save(context, x => x.Id);
return Task.CompletedTask;
}
/// <inheritdoc />
public Task<WorkflowExecutionContext?> FindAsync(string workflowExecutionContextId)
{
var result = _store.Find((context) => context.Id == workflowExecutionContextId);
return Task.FromResult(result);
}
/// <inheritdoc />
public Task DeleteAsync(string workflowExecutionContextId)
{
_store.Delete(workflowExecutionContextId);
return Task.CompletedTask;
}
}

View file

@ -14,7 +14,7 @@ public class StoreWorkflowExecutionLogSink(IWorkflowExecutionLogStore store, IWo
public async Task PersistExecutionLogsAsync(WorkflowExecutionContext context, CancellationToken cancellationToken)
{
var records = extractor.ExtractWorkflowExecutionLogs(context).ToList();
await store.AddManyAsync(records, context.CancellationTokens.SystemCancellationToken);
await notificationSender.SendAsync(new WorkflowExecutionLogUpdated(context), context.CancellationTokens.SystemCancellationToken);
await store.AddManyAsync(records, context.CancellationToken);
await notificationSender.SendAsync(new WorkflowExecutionLogUpdated(context), context.CancellationToken);
}
}

View file

@ -1,6 +1,5 @@
using Elsa.Workflows.ComponentTests.Helpers.Fixtures;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace Elsa.Workflows.ComponentTests;
@ -12,13 +11,13 @@ public abstract class AppComponentTest(App app) : IDisposable
protected Infrastructure Infrastructure { get; } = app.Infrastructure;
protected IServiceScope Scope { get; } = app.WorkflowServer.Services.CreateScope();
protected virtual void OnDispose()
{
}
void IDisposable.Dispose()
{
Scope.Dispose();
OnDispose();
}
protected virtual void OnDispose()
{
}
}

View file

@ -1,7 +1,5 @@
using Elsa.Workflows.ComponentTests.Helpers.Fixtures;
using Hangfire.Annotations;
using JetBrains.Annotations;
using Xunit;
namespace Elsa.Workflows.ComponentTests;

View file

@ -1,7 +1,6 @@
using System.Net.Http.Headers;
using System.Reflection;
using Elsa.Alterations.Extensions;
using Elsa.Common.Contracts;
using Elsa.EntityFrameworkCore.Extensions;
using Elsa.EntityFrameworkCore.Modules.Alterations;
using Elsa.EntityFrameworkCore.Modules.Identity;
@ -17,6 +16,8 @@ using Elsa.Testing.Shared.Services;
using Elsa.Workflows.ComponentTests.Consumers;
using Elsa.Workflows.ComponentTests.Helpers.Materializers;
using Elsa.Workflows.ComponentTests.Helpers.Services;
using Elsa.Workflows.ComponentTests.Helpers.WorkflowProviders;
using Elsa.Workflows.Management;
using Elsa.Workflows.Runtime.Distributed.Extensions;
using FluentStorage;
using Hangfire.Annotations;

View file

@ -1,13 +1,13 @@
using Elsa.Workflows.Activities;
using Elsa.Workflows.ComponentTests.Helpers.WorkflowProviders;
using Elsa.Workflows.Management.Contracts;
using Elsa.Workflows.Management;
using Elsa.Workflows.Management.Entities;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime;
namespace Elsa.Workflows.ComponentTests.Helpers.Materializers;
/// A workflow materializer that deserializes workflows created from <see cref="TestWorkflowProvider"/>.
public class TestWorkflowMaterializer(IEnumerable<IWorkflowProvider> workflowProviders) : IWorkflowMaterializer
public class TestWorkflowMaterializer(IEnumerable<IWorkflowsProvider> workflowProviders) : IWorkflowMaterializer
{
/// The name of the materializer.
public const string MaterializerName = "Test";

View file

@ -1,12 +1,12 @@
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Models;
using Elsa.Workflows.Runtime;
namespace Elsa.Workflows.ComponentTests.Helpers.WorkflowProviders;
public class TestWorkflowProvider : IWorkflowProvider
public class TestWorkflowProvider : IWorkflowsProvider
{
public string Name => "Test";
public ICollection<MaterializedWorkflow> MaterializedWorkflows { get; set; } = new List<MaterializedWorkflow>();
public string Name => "Test";
public ValueTask<IEnumerable<MaterializedWorkflow>> GetWorkflowsAsync(CancellationToken cancellationToken = default)
{
return new(MaterializedWorkflows);

View file

@ -2,7 +2,6 @@ using Elsa.Expressions.Helpers;
using Elsa.Extensions;
using Elsa.Workflows.ComponentTests.Scenarios.Variables.Workflows;
using Elsa.Workflows.Management;
using Elsa.Workflows.Management.Contracts;
using Elsa.Workflows.Models;
using Elsa.Workflows.Runtime;
using Elsa.Workflows.Runtime.Entities;

View file

@ -2,7 +2,6 @@ using Elsa.Http.Contracts;
using Elsa.Testing.Shared;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Management;
using Elsa.Workflows.Management.Contracts;
using Elsa.Workflows.Runtime.Filters;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
@ -11,37 +10,36 @@ namespace Elsa.Workflows.ComponentTests.Scenarios.WorkflowActivities;
public class AutoUpdateTests : AppComponentTest
{
private readonly IMemoryCache _cache;
private readonly IHasher _hasher;
private readonly IWorkflowDefinitionCacheManager _definitionCacheManager;
private readonly IWorkflowDefinitionPublisher _publisher;
private readonly ISignalManager _signalManager;
private readonly ITriggerChangeTokenSignalEvents _changeTokenEvents;
private readonly IHttpWorkflowsCacheManager _httpCacheManager;
private readonly IWorkflowDefinitionCacheManager _workflowCacheManager;
private string? _httpChangeToken;
private string? _triggerChangeToken;
private string? _graphChangeToken;
private static readonly object HttpChangeTokenSignal = new();
private static readonly object TriggerChangeTokenSignal = new();
private static readonly object GraphChangeTokenSignal = new();
private const string ParentDefinitionVersionId = "4b584e249fdca951";
private const string ParentDefinitionId = "878770f04439a55d";
private const string ChildDefinitionId = "f353742a9ef6af4";
private static readonly object HttpChangeTokenSignal = new();
private static readonly object TriggerChangeTokenSignal = new();
private static readonly object GraphChangeTokenSignal = new();
private readonly IMemoryCache _cache;
private readonly ITriggerChangeTokenSignalEvents _changeTokenEvents;
private readonly IWorkflowDefinitionCacheManager _definitionCacheManager;
private readonly IHasher _hasher;
private readonly IHttpWorkflowsCacheManager _httpCacheManager;
private readonly IWorkflowDefinitionPublisher _publisher;
private readonly ISignalManager _signalManager;
private readonly IWorkflowDefinitionCacheManager _workflowCacheManager;
private string? _graphChangeToken;
private string? _httpChangeToken;
private string? _triggerChangeToken;
public AutoUpdateTests(App app) : base(app)
{
_cache = Scope.ServiceProvider.GetRequiredService<IMemoryCache>();
_hasher = Scope.ServiceProvider.GetRequiredService<IHasher>();
_definitionCacheManager = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionCacheManager>();
_publisher = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionPublisher>();
_httpCacheManager = Scope.ServiceProvider.GetRequiredService<IHttpWorkflowsCacheManager>();
_workflowCacheManager = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionCacheManager>();
_signalManager = Scope.ServiceProvider.GetRequiredService<ISignalManager>();
_changeTokenEvents = Scope.ServiceProvider.GetRequiredService<ITriggerChangeTokenSignalEvents>();
_changeTokenEvents.ChangeTokenSignalTriggered += OnChangeTokenSignalTriggered;
@ -53,7 +51,7 @@ public class AutoUpdateTests : AppComponentTest
//Run workflow to make sure the all required items for running the workflow are in the cache
var client = WorkflowServer.CreateHttpWorkflowClient();
await client.GetStringAsync("test-cache-invalidation");
//Make sure the items are in the cache
var hash = _httpCacheManager.ComputeBookmarkHash("/test-cache-invalidation", "get");
Assert.True(_cache.TryGetValue($"http-workflow:{hash}", out _));
@ -67,15 +65,15 @@ public class AutoUpdateTests : AppComponentTest
var parentVersionCacheKey = _definitionCacheManager.CreateWorkflowVersionCacheKey(ParentDefinitionVersionId);
Assert.True(_cache.TryGetValue(parentVersionCacheKey, out _));
//Set change tokens
_httpChangeToken = _workflowCacheManager.CreateWorkflowDefinitionChangeTokenKey(ParentDefinitionId);
_triggerChangeToken = _httpCacheManager.GetTriggerChangeTokenKey(hash);
_graphChangeToken = _workflowCacheManager.CreateWorkflowDefinitionChangeTokenKey(ParentDefinitionId);
//(Act) Save the draft version of the child workflow and update the references
await _publisher.PublishAsync(ChildDefinitionId);
//Wait till the notifications for updating the cache have been send and check the cache.
await _signalManager.WaitAsync<TriggerChangeTokenSignalEventArgs>(HttpChangeTokenSignal);
await _signalManager.WaitAsync<TriggerChangeTokenSignalEventArgs>(TriggerChangeTokenSignal);
@ -92,10 +90,12 @@ public class AutoUpdateTests : AppComponentTest
{
_signalManager.Trigger(HttpChangeTokenSignal, args);
}
if (args.Key == _triggerChangeToken)
{
_signalManager.Trigger(TriggerChangeTokenSignal, args);
}
if (args.Key == _graphChangeToken)
{
_signalManager.Trigger(GraphChangeTokenSignal, args);

View file

@ -1,20 +1,20 @@
using Elsa.Testing.Shared;
using Elsa.Workflows.ComponentTests.Scenarios.WorkflowActivities.Workflows;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Management;
using Elsa.Workflows.Management.Contracts;
using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Workflows.ComponentTests.Scenarios.WorkflowActivities;
public class DeleteWorkflowTests : AppComponentTest
{
private readonly ISignalManager _signalManager;
private readonly IWorkflowDefinitionEvents _workflowDefinitionEvents;
private static readonly object WorkflowDeletedSignal = new();
private readonly IServiceScope _scope1;
private readonly IServiceScope _scope2;
private readonly IServiceScope _scope3;
private static readonly object WorkflowDeletedSignal = new();
private readonly ISignalManager _signalManager;
private readonly IWorkflowDefinitionEvents _workflowDefinitionEvents;
public DeleteWorkflowTests(App app) : base(app)
{
_scope1 = app.Cluster.Pod1.Services.CreateScope();
@ -30,28 +30,28 @@ public class DeleteWorkflowTests : AppComponentTest
public async Task DeleteWorkflow()
{
EnsureWorkflowInRegistry(_scope1, Workflows.DeleteWorkflow.Type);
var workflowDefinitionManager = _scope1.ServiceProvider.GetRequiredService<IWorkflowDefinitionManager>();
await workflowDefinitionManager.DeleteByDefinitionIdAsync(Workflows.DeleteWorkflow.DefinitionId);
WorkflowTypeDeletedFromRegistry(_scope1, Workflows.DeleteWorkflow.Type);
}
[Fact(Skip = "Clustered tests are interfering with other event driven tests")]
public async Task DeleteWorkflow_Clustered()
{
EnsureWorkflowInRegistry(_scope1, Workflows.DeleteWorkflowClustered.Type);
EnsureWorkflowInRegistry(_scope2, Workflows.DeleteWorkflowClustered.Type);
EnsureWorkflowInRegistry(_scope3, Workflows.DeleteWorkflowClustered.Type);
EnsureWorkflowInRegistry(_scope1, DeleteWorkflowClustered.Type);
EnsureWorkflowInRegistry(_scope2, DeleteWorkflowClustered.Type);
EnsureWorkflowInRegistry(_scope3, DeleteWorkflowClustered.Type);
var workflowDefinitionManager = _scope1.ServiceProvider.GetRequiredService<IWorkflowDefinitionManager>();
await workflowDefinitionManager.DeleteByDefinitionIdAsync(Workflows.DeleteWorkflowClustered.DefinitionId);
WorkflowTypeDeletedFromRegistry(_scope1, Workflows.DeleteWorkflowClustered.Type);
await workflowDefinitionManager.DeleteByDefinitionIdAsync(DeleteWorkflowClustered.DefinitionId);
WorkflowTypeDeletedFromRegistry(_scope1, DeleteWorkflowClustered.Type);
await _signalManager.WaitAsync<WorkflowDefinitionDeletedEventArgs>(WorkflowDeletedSignal);
WorkflowTypeDeletedFromRegistry(_scope2, Workflows.DeleteWorkflowClustered.Type);
WorkflowTypeDeletedFromRegistry(_scope3, Workflows.DeleteWorkflowClustered.Type);
WorkflowTypeDeletedFromRegistry(_scope2, DeleteWorkflowClustered.Type);
WorkflowTypeDeletedFromRegistry(_scope3, DeleteWorkflowClustered.Type);
}
private static void EnsureWorkflowInRegistry(IServiceScope scope, string type)

View file

@ -1,7 +1,6 @@
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Management;
using Elsa.Workflows.Management.Activities.WorkflowDefinitionActivity;
using Elsa.Workflows.Management.Contracts;
using Elsa.Workflows.Management.Models;
using Elsa.Workflows.Models;
using Microsoft.Extensions.DependencyInjection;
@ -18,11 +17,11 @@ public class SaveWorkflowTests(App app) : AppComponentTest(app)
public async Task ActivityRegistry(string name, bool usableAsActivity, bool publish, bool expectedInRegistry, bool isBrowsable)
{
var activityRegistry = Scope.ServiceProvider.GetRequiredService<IActivityRegistry>();
var descriptor = activityRegistry.Find(name);
if (descriptor is not null)
activityRegistry.Remove(typeof(WorkflowDefinitionActivityProvider), descriptor);
var importer = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionImporter>();
var request = new SaveWorkflowDefinitionRequest
{
@ -39,7 +38,7 @@ public class SaveWorkflowTests(App app) : AppComponentTest(app)
Publish = publish
};
await importer.ImportAsync(request);
descriptor = activityRegistry.Find(name);
if (expectedInRegistry)
@ -49,7 +48,7 @@ public class SaveWorkflowTests(App app) : AppComponentTest(app)
}
else
{
Assert.Null(descriptor);
Assert.Null(descriptor);
}
}
}

View file

@ -5,10 +5,8 @@ using Elsa.Workflows.ComponentTests.Helpers.Materializers;
using Elsa.Workflows.ComponentTests.Helpers.WorkflowProviders;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Management;
using Elsa.Workflows.Management.Contracts;
using Elsa.Workflows.Management.Materializers;
using Elsa.Workflows.Runtime;
using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Models;
using Humanizer;
using Microsoft.Extensions.DependencyInjection;
@ -16,12 +14,12 @@ namespace Elsa.Workflows.ComponentTests.Scenarios.WorkflowDefinitionReload;
public class ReloadWorkflowTests : AppComponentTest
{
private readonly IWorkflowDefinitionManager _workflowDefinitionManager;
private readonly IWorkflowDefinitionsReloader _workflowDefinitionsReloader;
private readonly IWorkflowBuilderFactory _workflowBuilderFactory;
private readonly TestWorkflowProvider _testWorkflowProvider;
private readonly IWorkflowDefinitionService _workflowDefinitionService;
private readonly IActivityRegistry _activityRegistry;
private readonly TestWorkflowProvider _testWorkflowProvider;
private readonly IWorkflowBuilderFactory _workflowBuilderFactory;
private readonly IWorkflowDefinitionManager _workflowDefinitionManager;
private readonly IWorkflowDefinitionService _workflowDefinitionService;
private readonly IWorkflowDefinitionsReloader _workflowDefinitionsReloader;
public ReloadWorkflowTests(App app) : base(app)
{
@ -30,8 +28,8 @@ public class ReloadWorkflowTests : AppComponentTest
_workflowBuilderFactory = Scope.ServiceProvider.GetRequiredService<IWorkflowBuilderFactory>();
_workflowDefinitionService = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionService>();
_activityRegistry = Scope.ServiceProvider.GetRequiredService<IActivityRegistry>();
var workflowProviders = Scope.ServiceProvider.GetRequiredService<IEnumerable<IWorkflowProvider>>();
_testWorkflowProvider = (TestWorkflowProvider)workflowProviders.First(x => x is TestWorkflowProvider);
var workflowsProviders = Scope.ServiceProvider.GetRequiredService<IEnumerable<IWorkflowsProvider>>();
_testWorkflowProvider = (TestWorkflowProvider)workflowsProviders.First(x => x is TestWorkflowProvider);
}
[Fact]
@ -52,53 +50,53 @@ public class ReloadWorkflowTests : AppComponentTest
var definitionId = Guid.NewGuid().ToString();
var definitionVersionId1 = Guid.NewGuid().ToString();
var workflowV1 = await BuildWorkflowAsync(definitionId, definitionVersionId1, 1);
// Set up the initial workflow version.
_testWorkflowProvider.MaterializedWorkflows = [workflowV1];
await _workflowDefinitionsReloader.ReloadWorkflowDefinitionsAsync();
var definitionV1 = await _workflowDefinitionService.FindWorkflowGraphAsync(definitionId, VersionOptions.Latest);
Assert.Equal(definitionVersionId1, definitionV1!.Workflow.Identity.Id);
// Simulate the workflow provider to have a new version available.
var definitionVersionId2 = Guid.NewGuid().ToString();
var workflowV2 = await BuildWorkflowAsync(definitionId, definitionVersionId2, 2);
_testWorkflowProvider.MaterializedWorkflows = [workflowV1, workflowV2];
// Reload the workflow definitions.
await _workflowDefinitionsReloader.ReloadWorkflowDefinitionsAsync();
// Assert that the workflow definition service finds the updated workflow version.
var definitionV2 = await _workflowDefinitionService.FindWorkflowGraphAsync(definitionId, VersionOptions.Latest);
Assert.Equal(definitionVersionId2, definitionV2!.Workflow.Identity.Id);
}
[Fact]
public async Task Reloading_AfterUpdatingSourceProvider_ShouldRefreshActivityRegistry()
{
var definitionId = Guid.NewGuid().ToString();
var definitionVersionId1 = Guid.NewGuid().ToString();
var workflowV1 = await BuildWorkflowAsync(definitionId, definitionVersionId1, 1);
// Set up the initial workflow version.
_testWorkflowProvider.MaterializedWorkflows = [workflowV1];
await _workflowDefinitionsReloader.ReloadWorkflowDefinitionsAsync();
var activityTypeName = workflowV1.Workflow.Name.Pascalize();
var activityV1 = _activityRegistry.Find(activityTypeName);
var activityV1 = _activityRegistry.Find(activityTypeName);
Assert.Equal(1, activityV1!.Version);
// Simulate the workflow provider to have a new version available.
var definitionVersionId2 = Guid.NewGuid().ToString();
var workflowV2 = await BuildWorkflowAsync(definitionId, definitionVersionId2, 2);
_testWorkflowProvider.MaterializedWorkflows = [workflowV1, workflowV2];
// Reload the workflow definitions.
await _workflowDefinitionsReloader.ReloadWorkflowDefinitionsAsync();
// Assert that the activity registry contains a new activity descriptor representing the new workflow version.
var activityV2 = _activityRegistry.Find(activityTypeName)!;
Assert.Equal(2, activityV2.Version);
}
private async Task<MaterializedWorkflow> BuildWorkflowAsync(string definitionId, string definitionVersionId, int version)
{
var builder = _workflowBuilderFactory.CreateBuilder();