diff --git a/SKILL.md b/SKILL.md index 31108d1..b65779d 100644 --- a/SKILL.md +++ b/SKILL.md @@ -456,6 +456,8 @@ services services.RegisterWorkflow(); ``` +`RegisterWaiter` and `ISignalStore` are registered only by `AddSignalWait`. Projects that call `AddConductorSharpPatterns()` or `AddCSharpLambdaTasks()` without `AddSignalWait` need no signal store. + **Important**: The `InMemorySignalStore` is only suitable for development/testing. For production, implement `ISignalStore` with a persistent backend (database, Redis, etc.) to ensure signals survive process restarts and work across multiple instances. #### Using Signal Wait in a Workflow diff --git a/src/ConductorSharp.Client/ConductorSharp.Client.csproj b/src/ConductorSharp.Client/ConductorSharp.Client.csproj index 8e698cc..1a50664 100644 --- a/src/ConductorSharp.Client/ConductorSharp.Client.csproj +++ b/src/ConductorSharp.Client/ConductorSharp.Client.csproj @@ -6,7 +6,7 @@ Codaxy Codaxy ConductorSharp.Client - 4.4.0 + 4.4.1 Client library for Netflix Conductor, with some additional quality of life features. https://github.com/codaxy/conductor-sharp netflix;conductor diff --git a/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj b/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj index d091539..df478ce 100644 --- a/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj +++ b/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj @@ -6,7 +6,7 @@ Codaxy Codaxy ConductorSharp.Engine - 4.4.0 + 4.4.1 Client library for Netflix Conductor, with some additional quality of life features. https://github.com/codaxy/conductor-sharp netflix;conductor diff --git a/src/ConductorSharp.KafkaCancellationNotifier/ConductorSharp.KafkaCancellationNotifier.csproj b/src/ConductorSharp.KafkaCancellationNotifier/ConductorSharp.KafkaCancellationNotifier.csproj index c7033c9..989e052 100644 --- a/src/ConductorSharp.KafkaCancellationNotifier/ConductorSharp.KafkaCancellationNotifier.csproj +++ b/src/ConductorSharp.KafkaCancellationNotifier/ConductorSharp.KafkaCancellationNotifier.csproj @@ -4,7 +4,7 @@ net6.0 enable enable - 4.4.0 + 4.4.1 Codaxy Codaxy diff --git a/src/ConductorSharp.Patterns/ConductorSharp.Patterns.csproj b/src/ConductorSharp.Patterns/ConductorSharp.Patterns.csproj index 7e05ca5..70163e9 100644 --- a/src/ConductorSharp.Patterns/ConductorSharp.Patterns.csproj +++ b/src/ConductorSharp.Patterns/ConductorSharp.Patterns.csproj @@ -7,7 +7,7 @@ False Codaxy Codaxy - 4.4.0 + 4.4.1 diff --git a/src/ConductorSharp.Patterns/Extensions/ContainerBuilderExtensions.cs b/src/ConductorSharp.Patterns/Extensions/ContainerBuilderExtensions.cs index cfd2a94..17d8c26 100644 --- a/src/ConductorSharp.Patterns/Extensions/ContainerBuilderExtensions.cs +++ b/src/ConductorSharp.Patterns/Extensions/ContainerBuilderExtensions.cs @@ -1,3 +1,4 @@ +using System.Reflection; using ConductorSharp.Engine.Extensions; using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Util; @@ -16,7 +17,7 @@ public static IExecutionManagerBuilder AddConductorSharpPatterns(this IExecution executionManagerBuilder.Builder.RegisterWorkerTask(); executionManagerBuilder.Builder.RegisterWorkerTask(); executionManagerBuilder.Builder.RegisterWorkerTask(); - executionManagerBuilder.Builder.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(typeof(WaitSeconds).Assembly)); + executionManagerBuilder.Builder.AddMediatR(cfg => RegisterPatternHandlers(cfg, typeof(WaitSeconds).Assembly)); return executionManagerBuilder; } @@ -30,7 +31,7 @@ public static IExecutionManagerBuilder AddCSharpLambdaTasks( { options.OwnerEmail = "owneremail@gmail.com"; }); - executionManagerBuilder.Builder.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(typeof(CSharpLambdaTask).Assembly)); + executionManagerBuilder.Builder.AddMediatR(cfg => RegisterPatternHandlers(cfg, typeof(CSharpLambdaTask).Assembly)); executionManagerBuilder.Builder.AddSingleton( new ConfigurationProperty(CSharpLambdaTask.LambdaTaskNameConfigurationProperty, csharpLambdaTaskNamePrefix) ); @@ -95,5 +96,13 @@ public static IExecutionManagerBuilder AddSignalWait( return executionManagerBuilder; } + + // RegisterWaiter depends on ISignalStore, which only AddSignalWait registers, + // so the other registrations leave it out of the assembly scan. + private static void RegisterPatternHandlers(MediatRServiceConfiguration cfg, Assembly assembly) + { + cfg.RegisterServicesFromAssemblies(assembly); + cfg.TypeEvaluator = type => type != typeof(RegisterWaiter); + } } } diff --git a/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj b/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj index 1359741..0b48430 100644 --- a/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj +++ b/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj @@ -7,7 +7,7 @@ disable true dotnet-conductorsharp - 4.4.0 + 4.4.1 diff --git a/test/ConductorSharp.Engine.Tests/Unit/PatternsRegistrationTests.cs b/test/ConductorSharp.Engine.Tests/Unit/PatternsRegistrationTests.cs new file mode 100644 index 0000000..5998243 --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/Unit/PatternsRegistrationTests.cs @@ -0,0 +1,63 @@ +using ConductorSharp.Engine.Extensions; +using ConductorSharp.Engine.Interface; +using ConductorSharp.Patterns.Extensions; +using ConductorSharp.Patterns.Services; +using ConductorSharp.Patterns.Tasks; +using MediatR; +using Microsoft.Extensions.DependencyInjection; + +namespace ConductorSharp.Engine.Tests.Unit +{ + public class PatternsRegistrationTests + { + private static readonly ServiceProviderOptions ValidateOnBuild = new() { ValidateOnBuild = true, ValidateScopes = true }; + + private static (IServiceCollection Services, IExecutionManagerBuilder Builder) CreateBuilder() + { + var services = new ServiceCollection(); + var builder = services + .AddConductorSharp(baseUrl: "http://empty/empty") + .AddExecutionManager( + maxConcurrentWorkers: 1, + sleepInterval: 1, + longPollInterval: 1, + domain: null, + handlerAssemblies: typeof(PatternsRegistrationTests).Assembly + ); + + return (services, builder); + } + + [Fact] + public void PatternsWithoutSignalWaitDoNotRequireSignalStore() + { + var (services, builder) = CreateBuilder(); + builder.AddConductorSharpPatterns().AddCSharpLambdaTasks(); + + using var provider = services.BuildServiceProvider(ValidateOnBuild); + + Assert.DoesNotContain(services, d => d.ImplementationType == typeof(RegisterWaiter)); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void SignalWaitRegistersRegisterWaiterHandler(bool signalWaitFirst) + { + var (services, builder) = CreateBuilder(); + if (signalWaitFirst) + builder.AddSignalWait().AddConductorSharpPatterns().AddCSharpLambdaTasks(); + else + builder.AddConductorSharpPatterns().AddCSharpLambdaTasks().AddSignalWait(); + + using var provider = services.BuildServiceProvider(ValidateOnBuild); + + Assert.Contains( + services, + d => + d.ServiceType == typeof(IRequestHandler) + && d.ImplementationType == typeof(RegisterWaiter) + ); + } + } +}