From 098e1a69543c1666cbe72142a04eaeec0471a602 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Thu, 19 Jun 2025 15:48:35 +0200 Subject: [PATCH 01/35] Implement initial version of invoker mechanism --- .../Behaviors/PrepareEmailBehavior.cs | 9 +- .../Behaviors/ValidationBehavior.cs | 21 +-- .../Extensions/IPipelineBuilder.cs | 8 +- .../Extensions/PipelineBuilder.cs | 22 ++-- .../Extensions/TaskRegistrationExtensions.cs | 7 +- .../Interface/INgWorker.cs | 11 ++ .../Interface/INgWorkerMiddleware.cs | 12 ++ .../Service/WorkerInvokerService.cs | 121 ++++++++++++++++++ .../Integration/UtilityTests.cs | 72 ++++++++++- 9 files changed, 253 insertions(+), 30 deletions(-) create mode 100644 src/ConductorSharp.Engine/Interface/INgWorker.cs create mode 100644 src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs create mode 100644 src/ConductorSharp.Engine/Service/WorkerInvokerService.cs diff --git a/examples/ConductorSharp.NoApi/Behaviors/PrepareEmailBehavior.cs b/examples/ConductorSharp.NoApi/Behaviors/PrepareEmailBehavior.cs index 33e1845b..0ebc7922 100644 --- a/examples/ConductorSharp.NoApi/Behaviors/PrepareEmailBehavior.cs +++ b/examples/ConductorSharp.NoApi/Behaviors/PrepareEmailBehavior.cs @@ -1,10 +1,11 @@ -using ConductorSharp.NoApi.Handlers; +using ConductorSharp.Engine.Interface; +using ConductorSharp.NoApi.Handlers; using MediatR; using Microsoft.Extensions.Logging; namespace ConductorSharp.NoApi.Behaviors { - internal class PrepareEmailBehavior : IPipelineBehavior + internal class PrepareEmailBehavior : INgWorkerMiddleware { private readonly ILogger _logger; @@ -15,12 +16,12 @@ public PrepareEmailBehavior(ILogger logger) public async Task Handle( PrepareEmailRequest request, - RequestHandlerDelegate next, + Func> next, CancellationToken cancellationToken ) { _logger.LogInformation($"Executed only before {nameof(PrepareEmailHandler)}"); - var response = await next(); + var response = await next(request, cancellationToken); _logger.LogInformation($"Executed only after {nameof(PrepareEmailHandler)}"); return response; } diff --git a/src/ConductorSharp.Engine/Behaviors/ValidationBehavior.cs b/src/ConductorSharp.Engine/Behaviors/ValidationBehavior.cs index 2185e4e6..0b2eefc7 100644 --- a/src/ConductorSharp.Engine/Behaviors/ValidationBehavior.cs +++ b/src/ConductorSharp.Engine/Behaviors/ValidationBehavior.cs @@ -1,20 +1,23 @@ -using ConductorSharp.Engine.Util; -using MediatR; +using System; using System.Threading; using System.Threading.Tasks; +using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; namespace ConductorSharp.Engine.Behaviors { - public class ValidationBehavior : IPipelineBehavior where TRequest : IRequest + public class ValidationWorkerMiddleware : INgWorkerMiddleware + where TRequest : class, new() + where TResponse : class, new() { - public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) + public async Task Handle( + TRequest request, + Func> next, + CancellationToken cancellationToken + ) { ObjectValidator.Validate(request); - - var response = await next(); - - ObjectValidator.Validate(response); - + var response = await next(request, cancellationToken); return response; } } diff --git a/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs index 70bfadc7..9430cce5 100644 --- a/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs @@ -1,5 +1,5 @@ using System; -using MediatR; +using ConductorSharp.Engine.Interface; namespace ConductorSharp.Engine.Extensions { @@ -10,7 +10,9 @@ public interface IPipelineBuilder void AddContextLogging(); void AddExecutionTaskTracking(); void AddCustomBehavior(Type behaviorType); - void AddCustomBehavior() - where TBehavior : class, IPipelineBehavior; + void AddCustomBehavior() + where TWorkerMiddleware : class, INgWorkerMiddleware + where TRequest : class, new() + where TResponse : class, new(); } } diff --git a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs index 9c8f6072..a846cfd3 100644 --- a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs @@ -1,7 +1,6 @@ using System; -using System.Reflection; using ConductorSharp.Engine.Behaviors; -using MediatR; +using ConductorSharp.Engine.Interface; using Microsoft.Extensions.DependencyInjection; namespace ConductorSharp.Engine.Extensions; @@ -9,19 +8,22 @@ namespace ConductorSharp.Engine.Extensions; internal class PipelineBuilder(IServiceCollection serviceCollection) : IPipelineBuilder { public void AddRequestResponseLogging() => - serviceCollection.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestResponseLoggingBehavior<,>)); + serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(RequestResponseLoggingBehavior<,>)); - public void AddValidation() => serviceCollection.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>)); + public void AddValidation() => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(ValidationWorkerMiddleware<,>)); - public void AddContextLogging() => serviceCollection.AddTransient(typeof(IPipelineBehavior<,>), typeof(ContextLoggingBehavior<,>)); + public void AddContextLogging() => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(ContextLoggingBehavior<,>)); - public void AddExecutionTaskTracking() => serviceCollection.AddTransient(typeof(IPipelineBehavior<,>), typeof(TaskExecutionTrackingBehavior<,>)); + public void AddExecutionTaskTracking() => + serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(TaskExecutionTrackingBehavior<,>)); - public void AddCustomBehavior(Type behaviorType) => serviceCollection.AddTransient(typeof(IPipelineBehavior<,>), behaviorType); + public void AddCustomBehavior(Type behaviorType) => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), behaviorType); - public void AddCustomBehavior() - where TBehavior : class, IPipelineBehavior + public void AddCustomBehavior() + where TWorkerMiddleware : class, INgWorkerMiddleware + where TRequest : class, new() + where TResponse : class, new() { - serviceCollection.AddTransient, TBehavior>(); + serviceCollection.AddTransient, TWorkerMiddleware>(); } } diff --git a/src/ConductorSharp.Engine/Extensions/TaskRegistrationExtensions.cs b/src/ConductorSharp.Engine/Extensions/TaskRegistrationExtensions.cs index a9833345..1e5b22ed 100644 --- a/src/ConductorSharp.Engine/Extensions/TaskRegistrationExtensions.cs +++ b/src/ConductorSharp.Engine/Extensions/TaskRegistrationExtensions.cs @@ -2,7 +2,6 @@ using System.Reflection; using ConductorSharp.Engine.Builders; using ConductorSharp.Engine.Builders.Metadata; -using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; using Microsoft.Extensions.DependencyInjection; @@ -11,7 +10,9 @@ namespace ConductorSharp.Engine.Extensions public static class TaskRegistrationExtensions { public static void RegisterWorkerTask(this IServiceCollection builder, Action updateOptions = null) - where TWorkerTask : IWorker + where TWorkerTask : class + // TODO: MR Removal + //where TWorkerTask : IWorker { builder.AddSingleton(ctx => ctx.GetRequiredService().Build(updateOptions)); @@ -24,6 +25,8 @@ public static void RegisterWorkerTask(this IServiceCollection build TaskDomain = GetTaskDomain(typeof(TWorkerTask)) } ); + + builder.AddTransient(); } private static string GetTaskDomain(Type workerType) => workerType.GetCustomAttribute()?.Domain; diff --git a/src/ConductorSharp.Engine/Interface/INgWorker.cs b/src/ConductorSharp.Engine/Interface/INgWorker.cs new file mode 100644 index 00000000..e51a7b0f --- /dev/null +++ b/src/ConductorSharp.Engine/Interface/INgWorker.cs @@ -0,0 +1,11 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace ConductorSharp.Engine.Interface; + +public interface INgWorker + where TRequest : class, new() + where TResponse : new() +{ + Task Handle(TRequest test, CancellationToken cancellationToken); +} diff --git a/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs b/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs new file mode 100644 index 00000000..8849ff97 --- /dev/null +++ b/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs @@ -0,0 +1,12 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace ConductorSharp.Engine.Interface; + +public interface INgWorkerMiddleware + where TRequest : class, new() + where TResponse : class, new() +{ + Task Handle(TRequest request, Func> next, CancellationToken cancellationToken); +} diff --git a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs new file mode 100644 index 00000000..d474ce31 --- /dev/null +++ b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs @@ -0,0 +1,121 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Reflection.Metadata; +using System.Threading; +using System.Threading.Tasks; +using ConductorSharp.Engine.Interface; +using Microsoft.Extensions.DependencyInjection; + +namespace ConductorSharp.Engine.Service +{ + public class WorkerInvokerService(IServiceProvider serviceProvider) + { + private record WorkerTypeInfo + { + public WorkerTypeInfo(Type workerType) + { + WorkerType = workerType; + (RequestType, ResponseType) = GetRequestResponseTypes(workerType); + MiddlewareType = typeof(INgWorkerMiddleware<,>).MakeGenericType(RequestType, ResponseType); + WorkerHandleMethod = typeof(INgWorker<,>) + .MakeGenericType(RequestType, ResponseType) + .GetMethod(nameof(INgWorker.Handle)); + MiddlewareHandleMethod = MiddlewareType.GetMethod(nameof(INgWorkerMiddleware.Handle)); + NextFuncType = MiddlewareHandleMethod!.GetParameters().FirstOrDefault(p => p.Name == "next")!.ParameterType; + TaskResultProperty = typeof(Task<>).MakeGenericType(ResponseType).GetProperty(nameof(Task.Result)); + } + + public Type WorkerType { get; } + public Type RequestType { get; } + public Type ResponseType { get; } + public Type MiddlewareType { get; } + public MethodInfo WorkerHandleMethod { get; } + public MethodInfo MiddlewareHandleMethod { get; } + public Type NextFuncType { get; } + public PropertyInfo TaskResultProperty { get; } + } + + private readonly IServiceProvider _serviceProvider = serviceProvider; + + public async Task Invoke(Type workerType, object request, CancellationToken cancellationToken) + { + var workerTypeInfo = new WorkerTypeInfo(workerType); + var middlewares = _serviceProvider.GetServices(workerTypeInfo.MiddlewareType).ToArray(); + var worker = _serviceProvider.GetRequiredService(workerType); + var resultTask = InvokeMiddlewarePipeline(middlewares, worker, workerTypeInfo, request, cancellationToken); + await resultTask; + var result = workerTypeInfo.TaskResultProperty.GetValue(resultTask); + return result; + } + + private static (Type RequestType, Type ResponseType) GetRequestResponseTypes(Type workerType) + { + var types = workerType.GetInterface(typeof(INgWorker<,>).Name)!.GetGenericArguments(); + return (types[0], types[1]); + } + + private static async Task InvokeHandler(object worker, object request, CancellationToken cancellationToken) + { + var resultTask = (Task)worker.GetType().GetMethod(nameof(INgWorker.Handle))!.Invoke(worker, [request, cancellationToken]); + await resultTask!; + + var propInfo = resultTask.GetType().GetProperty(nameof(Task.Result)); + var result = propInfo!.GetValue(resultTask); + + return Task.FromResult(result); + } + + private static Task InvokeMiddlewarePipeline( + object[] middlewares, + object worker, + WorkerTypeInfo workerTypeInfo, + object request, + CancellationToken cancellationToken + ) + { + object result; + if (middlewares.Length == 0) + result = workerTypeInfo.WorkerHandleMethod.Invoke(worker, [request, cancellationToken]); + else + result = workerTypeInfo.MiddlewareHandleMethod.Invoke( + middlewares[0], + [request, GenerateCallToMiddleware(middlewares, worker, 1, workerTypeInfo).Compile(), cancellationToken] + ); + + return (Task)result; + } + + private static LambdaExpression GenerateCallToHandler(object worker, WorkerTypeInfo workerInfo) + { + var requestParam = Expression.Parameter(workerInfo.RequestType); + var cancellationTokenParam = Expression.Parameter(typeof(CancellationToken)); + + var lambdaBody = Expression.Call(Expression.Constant(worker), workerInfo.WorkerHandleMethod, requestParam, cancellationTokenParam); + var lambda = Expression.Lambda(workerInfo.NextFuncType, lambdaBody, requestParam, cancellationTokenParam); + return lambda; + } + + private static LambdaExpression GenerateCallToMiddleware(object[] middlewares, object worker, int middlewareIndex, WorkerTypeInfo workerInfo) + { + if (middlewares.Length == middlewareIndex) + return GenerateCallToHandler(worker, workerInfo); + + var requestParam = Expression.Parameter(workerInfo.RequestType); + var cancellationTokenParam = Expression.Parameter(typeof(CancellationToken)); + + var nextLambda = GenerateCallToMiddleware(middlewares, worker, middlewareIndex + 1, workerInfo); + var lambdaBody = Expression.Call( + Expression.Constant(middlewares[middlewareIndex]), + workerInfo.MiddlewareHandleMethod, + requestParam, + nextLambda, + cancellationTokenParam + ); + var lambda = Expression.Lambda(workerInfo.NextFuncType, lambdaBody, requestParam, cancellationTokenParam); + return lambda; + } + } +} diff --git a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs index 54e503ce..a38f3ebd 100644 --- a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs +++ b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs @@ -1,9 +1,13 @@ -using ConductorSharp.Engine.Tests.Samples.Workflows; -using System; +using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; +using ConductorSharp.Engine.Extensions; +using ConductorSharp.Engine.Service; +using ConductorSharp.Engine.Tests.Samples.Workflows; +using Microsoft.Extensions.DependencyInjection; namespace ConductorSharp.Engine.Tests.Integration { @@ -15,5 +19,69 @@ public void NamingUtilShouldReturnCorrectNameableObjectName() Assert.Equal("TEST_StringInterpolation", NamingUtil.NameOf()); Assert.Equal("CUSTOMER_get", NamingUtil.NameOf()); } + + public class Request + { + public int Counter = 0; + + public class Response { } + + public class Handler : INgWorker + { + public Task Handle(Request request, CancellationToken cancellationToken) + { + request.Counter++; + return Task.FromResult(new Response()); + } + } + } + + public class Middleware : INgWorkerMiddleware + { + public async Task Handle( + Request request, + Func> next, + CancellationToken cancellationToken + ) + { + request.Counter++; + return await next(request, cancellationToken); + } + } + + public class GenericMiddleware : INgWorkerMiddleware + where TResponse : class, new() + where TRequest : class, new() + { + public async Task Handle( + TRequest request, + Func> next, + CancellationToken cancellationToken + ) + { + var obj = (object)request; + var req = (Request)obj; + req.Counter++; + return await next(request, cancellationToken); + } + } + + [Fact] + public async Task Test() + { + var collection = new ServiceCollection(); + collection.RegisterWorkerTask(); + collection.AddTransient, Middleware>(); + collection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(GenericMiddleware<,>)); + + var provider = collection.BuildServiceProvider(); + var invoker = new WorkerInvokerService(provider); + + var sw = Stopwatch.StartNew(); + var @ref = new Request(); + var result = await invoker.Invoke(typeof(Request.Handler), @ref, default); + var response = (Request.Response)result; + var t = sw.ElapsedMilliseconds; + } } } From b4d34ecf55ecd24fa70c2b9dd4c0b90205daaca5 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 20 Jun 2025 08:44:20 +0200 Subject: [PATCH 02/35] ... --- src/ConductorSharp.Engine/ExecutionManager.cs | 9 +++++---- .../Extensions/ConductorSharpBuilder.cs | 10 ++++------ .../Service/WorkerInvokerService.cs | 11 ++++++++++- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/ConductorSharp.Engine/ExecutionManager.cs b/src/ConductorSharp.Engine/ExecutionManager.cs index 4c58595c..e6bcc1eb 100644 --- a/src/ConductorSharp.Engine/ExecutionManager.cs +++ b/src/ConductorSharp.Engine/ExecutionManager.cs @@ -3,7 +3,6 @@ using System.IO; using System.Linq; using System.Threading; -using System.Threading.Tasks; using ConductorSharp.Client; using ConductorSharp.Client.Generated; using ConductorSharp.Client.Service; @@ -11,8 +10,8 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; using ConductorSharp.Engine.Polling; +using ConductorSharp.Engine.Service; using ConductorSharp.Engine.Util; -using MediatR; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json; @@ -32,6 +31,7 @@ internal class ExecutionManager : IExecutionManager private readonly IPollTimingStrategy _pollTimingStrategy; private readonly IPollOrderStrategy _pollOrderStrategy; private readonly ICancellationNotifier _cancellationNotifier; + private readonly WorkerInvokerService _workerInvokerService; public ExecutionManager( WorkerSetConfig options, @@ -42,7 +42,8 @@ public ExecutionManager( IServiceScopeFactory lifetimeScope, IPollTimingStrategy pollTimingStrategy, IPollOrderStrategy pollOrderStrategy, - ICancellationNotifier cancellationNotifier + ICancellationNotifier cancellationNotifier, + WorkerInvokerService workerInvokerService ) { _configuration = options; @@ -54,6 +55,7 @@ ICancellationNotifier cancellationNotifier _pollTimingStrategy = pollTimingStrategy; _pollOrderStrategy = pollOrderStrategy; _cancellationNotifier = cancellationNotifier; + _workerInvokerService = workerInvokerService; _externalPayloadService = externalPayloadService; } @@ -186,7 +188,6 @@ CancellationToken cancellationToken using var scope = _lifetimeScopeFactory.CreateScope(); var context = scope.ServiceProvider.GetService(); - var mediator = scope.ServiceProvider.GetRequiredService(); if (context != null) { diff --git a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs index 5c59e1e7..513f7f98 100644 --- a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs @@ -2,14 +2,12 @@ using System.Net.Http; using System.Reflection; using ConductorSharp.Client.Service; -using ConductorSharp.Engine.Behaviors; using ConductorSharp.Engine.Health; using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Polling; using ConductorSharp.Engine.Service; using ConductorSharp.Engine.Util; using ConductorSharp.Engine.Util.Builders; -using MediatR; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -43,7 +41,7 @@ params Assembly[] handlerAssemblies Builder.AddTransient(); - Builder.AddSingleton(); + Builder.AddSingleton(); Builder.AddScoped(); @@ -55,17 +53,17 @@ params Assembly[] handlerAssemblies Builder.AddSingleton(); - Builder.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(handlerAssemblies)); + Builder.AddTransient(); return this; } public IExecutionManagerBuilder UseBetaExecutionManager() { - Builder.AddSingleton(); + Builder.AddSingleton(); return this; } - + public IExecutionManagerBuilder AddPipelines(Action behaviorBuilder) { var pipelineBuilder = new PipelineBuilder(Builder); diff --git a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs index d474ce31..c29811f5 100644 --- a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs +++ b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs @@ -1,4 +1,6 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Linq.Expressions; @@ -40,7 +42,14 @@ public WorkerTypeInfo(Type workerType) private readonly IServiceProvider _serviceProvider = serviceProvider; - public async Task Invoke(Type workerType, object request, CancellationToken cancellationToken) + public async Task> Invoke( + Type workerType, + IDictionary request, + CancellationToken cancellationToken + ) { } + + // TODO: MR Removal: Make private + public async Task InternalInvoke(Type workerType, object request, CancellationToken cancellationToken) { var workerTypeInfo = new WorkerTypeInfo(workerType); var middlewares = _serviceProvider.GetServices(workerTypeInfo.MiddlewareType).ToArray(); From 1be8f42e6bd996633f49bbee0e658636fdaff829 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Tue, 24 Jun 2025 19:14:28 +0200 Subject: [PATCH 03/35] Migrate serilaziation/deserialization to invoker service --- src/ConductorSharp.Engine/ExecutionManager.cs | 22 +------- .../Service/WorkerInvokerService.cs | 52 +++++++++--------- .../TypePollSpreadingExecutionManager.cs | 54 +++++-------------- .../Integration/UtilityTests.cs | 18 +++---- 4 files changed, 46 insertions(+), 100 deletions(-) diff --git a/src/ConductorSharp.Engine/ExecutionManager.cs b/src/ConductorSharp.Engine/ExecutionManager.cs index e6bcc1eb..c1cede5f 100644 --- a/src/ConductorSharp.Engine/ExecutionManager.cs +++ b/src/ConductorSharp.Engine/ExecutionManager.cs @@ -100,20 +100,6 @@ private string GetQueueTaskName(TaskToWorker taskToWorker) return taskToWorker.TaskName; } - private static Type GetInputType(Type workerType) - { - var interfaces = workerType - .GetInterfaces() - .Where(a => a.IsGenericType && a.GetGenericTypeDefinition() == typeof(ITaskRequestHandler<,>)) - .First(); - var genericArguments = interfaces.GetGenericArguments(); - - var inputType = genericArguments[0]; - var outputType = genericArguments[1]; - - return inputType; - } - private async Task PollAndHandle(TaskToWorker scheduledWorker, CancellationToken cancellationToken) { Client.Generated.Task pollResponse; @@ -179,12 +165,6 @@ CancellationToken cancellationToken ); } - var inputType = GetInputType(scheduledWorker.TaskType); - var inputData = SerializationHelper.DictonaryToObject(inputType, pollResponse.InputData, ConductorConstants.IoJsonSerializerSettings); - // Poll response data can be huge (if read from external storage) - // We can save memory by not holding reference to pollResponse.InputData after it is parsed - pollResponse.InputData = null; - using var scope = _lifetimeScopeFactory.CreateScope(); var context = scope.ServiceProvider.GetService(); @@ -200,7 +180,7 @@ CancellationToken cancellationToken context.WorkerId = workerId; } - var response = await mediator.Send(inputData, tokenHolder.CancellationToken); + var response = await _workerInvokerService.Invoke(scheduledWorker.TaskType, pollResponse.InputData, tokenHolder.CancellationToken); await _taskManager.UpdateAsync( new TaskResult diff --git a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs index c29811f5..8f945283 100644 --- a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs +++ b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs @@ -6,8 +6,11 @@ using System.Linq.Expressions; using System.Reflection; using System.Reflection.Metadata; +using System.Runtime.InteropServices.ComTypes; using System.Threading; using System.Threading.Tasks; +using ConductorSharp.Client; +using ConductorSharp.Client.Util; using ConductorSharp.Engine.Interface; using Microsoft.Extensions.DependencyInjection; @@ -38,6 +41,12 @@ public WorkerTypeInfo(Type workerType) public MethodInfo MiddlewareHandleMethod { get; } public Type NextFuncType { get; } public PropertyInfo TaskResultProperty { get; } + + private static (Type RequestType, Type ResponseType) GetRequestResponseTypes(Type workerType) + { + var types = workerType.GetInterface(typeof(INgWorker<,>).Name)!.GetGenericArguments(); + return (types[0], types[1]); + } } private readonly IServiceProvider _serviceProvider = serviceProvider; @@ -46,37 +55,28 @@ public async Task> Invoke( Type workerType, IDictionary request, CancellationToken cancellationToken - ) { } - - // TODO: MR Removal: Make private - public async Task InternalInvoke(Type workerType, object request, CancellationToken cancellationToken) + ) { var workerTypeInfo = new WorkerTypeInfo(workerType); + var objRequest = SerializationHelper.DictonaryToObject(workerTypeInfo.RequestType, request, ConductorConstants.IoJsonSerializerSettings); + var sw = Stopwatch.StartNew(); + var objResponse = await InternalInvoke(workerTypeInfo, objRequest, cancellationToken); + var t = sw.ElapsedMilliseconds; + var response = SerializationHelper.ObjectToDictionary(objResponse, ConductorConstants.IoJsonSerializerSettings); + + return response; + } + + private async Task InternalInvoke(WorkerTypeInfo workerTypeInfo, object request, CancellationToken cancellationToken) + { var middlewares = _serviceProvider.GetServices(workerTypeInfo.MiddlewareType).ToArray(); - var worker = _serviceProvider.GetRequiredService(workerType); + var worker = _serviceProvider.GetRequiredService(workerTypeInfo.WorkerType); var resultTask = InvokeMiddlewarePipeline(middlewares, worker, workerTypeInfo, request, cancellationToken); await resultTask; var result = workerTypeInfo.TaskResultProperty.GetValue(resultTask); return result; } - private static (Type RequestType, Type ResponseType) GetRequestResponseTypes(Type workerType) - { - var types = workerType.GetInterface(typeof(INgWorker<,>).Name)!.GetGenericArguments(); - return (types[0], types[1]); - } - - private static async Task InvokeHandler(object worker, object request, CancellationToken cancellationToken) - { - var resultTask = (Task)worker.GetType().GetMethod(nameof(INgWorker.Handle))!.Invoke(worker, [request, cancellationToken]); - await resultTask!; - - var propInfo = resultTask.GetType().GetProperty(nameof(Task.Result)); - var result = propInfo!.GetValue(resultTask); - - return Task.FromResult(result); - } - private static Task InvokeMiddlewarePipeline( object[] middlewares, object worker, @@ -89,10 +89,10 @@ CancellationToken cancellationToken if (middlewares.Length == 0) result = workerTypeInfo.WorkerHandleMethod.Invoke(worker, [request, cancellationToken]); else - result = workerTypeInfo.MiddlewareHandleMethod.Invoke( - middlewares[0], - [request, GenerateCallToMiddleware(middlewares, worker, 1, workerTypeInfo).Compile(), cancellationToken] - ); + { + var next = GenerateCallToMiddleware(middlewares, worker, 1, workerTypeInfo).Compile(); + result = workerTypeInfo.MiddlewareHandleMethod.Invoke(middlewares[0], [request, next, cancellationToken]); + } return (Task)result; } diff --git a/src/ConductorSharp.Engine/TypePollSpreadingExecutionManager.cs b/src/ConductorSharp.Engine/TypePollSpreadingExecutionManager.cs index e3142841..42e54b31 100644 --- a/src/ConductorSharp.Engine/TypePollSpreadingExecutionManager.cs +++ b/src/ConductorSharp.Engine/TypePollSpreadingExecutionManager.cs @@ -3,7 +3,6 @@ using System.IO; using System.Linq; using System.Threading; -using System.Threading.Tasks; using ConductorSharp.Client; using ConductorSharp.Client.Generated; using ConductorSharp.Client.Service; @@ -11,8 +10,8 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; using ConductorSharp.Engine.Polling; +using ConductorSharp.Engine.Service; using ConductorSharp.Engine.Util; -using MediatR; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json; @@ -32,6 +31,7 @@ internal class TypePollSpreadingExecutionManager : IExecutionManager private readonly IPollTimingStrategy _pollTimingStrategy; private readonly IPollOrderStrategy _pollOrderStrategy; private readonly ICancellationNotifier _cancellationNotifier; + private readonly WorkerInvokerService _workerInvokerService; public TypePollSpreadingExecutionManager( WorkerSetConfig options, @@ -42,7 +42,8 @@ public TypePollSpreadingExecutionManager( IServiceScopeFactory lifetimeScope, IPollTimingStrategy pollTimingStrategy, IPollOrderStrategy pollOrderStrategy, - ICancellationNotifier cancellationNotifier + ICancellationNotifier cancellationNotifier, + WorkerInvokerService workerInvokerService ) { _configuration = options; @@ -54,6 +55,7 @@ ICancellationNotifier cancellationNotifier _pollTimingStrategy = pollTimingStrategy; _pollOrderStrategy = pollOrderStrategy; _cancellationNotifier = cancellationNotifier; + _workerInvokerService = workerInvokerService; _externalPayloadService = externalPayloadService; } @@ -67,8 +69,7 @@ public async Task StartAsync(CancellationToken cancellationToken) .Where(a => a.Value > 0) .ToDictionary(a => a.Key, a => a.Value); - var scheduledWorkers = _registeredWorkers.Where(a => queuedTasks.ContainsKey(GetQueueTaskName(a))) - .ToList(); + var scheduledWorkers = _registeredWorkers.Where(a => queuedTasks.ContainsKey(GetQueueTaskName(a))).ToList(); currentSleepInterval = _pollTimingStrategy.CalculateDelay( queuedTasks, @@ -77,8 +78,7 @@ public async Task StartAsync(CancellationToken cancellationToken) currentSleepInterval ); - scheduledWorkers = - _pollOrderStrategy.CalculateOrder(queuedTasks, scheduledWorkers, _semaphore.CurrentCount); + scheduledWorkers = _pollOrderStrategy.CalculateOrder(queuedTasks, scheduledWorkers, _semaphore.CurrentCount); foreach (var scheduledWorker in scheduledWorkers) { @@ -109,20 +109,6 @@ private string GetQueueTaskName(TaskToWorker taskToWorker) return taskToWorker.TaskName; } - private static Type GetInputType(Type workerType) - { - var interfaces = workerType - .GetInterfaces() - .Where(a => a.IsGenericType && a.GetGenericTypeDefinition() == typeof(ITaskRequestHandler<,>)) - .First(); - var genericArguments = interfaces.GetGenericArguments(); - - var inputType = genericArguments[0]; - var outputType = genericArguments[1]; - - return inputType; - } - private async Task PollAndHandle(TaskToWorker scheduledWorker, CancellationToken cancellationToken) { Client.Generated.Task pollResponse; @@ -177,8 +163,7 @@ CancellationToken cancellationToken ); // TODO: iffy - var file = await _externalPayloadService.GetExternalStorageDataAsync(externalStorageLocation.Path, - tokenHolder.CancellationToken); + var file = await _externalPayloadService.GetExternalStorageDataAsync(externalStorageLocation.Path, tokenHolder.CancellationToken); using TextReader textReader = new StreamReader(file.Stream); var json = await textReader.ReadToEndAsync(); @@ -189,17 +174,9 @@ CancellationToken cancellationToken ); } - var inputType = GetInputType(scheduledWorker.TaskType); - var inputData = SerializationHelper.DictonaryToObject(inputType, pollResponse.InputData, - ConductorConstants.IoJsonSerializerSettings); - // Poll response data can be huge (if read from external storage) - // We can save memory by not holding reference to pollResponse.InputData after it is parsed - pollResponse.InputData = null; - using var scope = _lifetimeScopeFactory.CreateScope(); var context = scope.ServiceProvider.GetService(); - var mediator = scope.ServiceProvider.GetRequiredService(); if (context != null) { @@ -212,16 +189,14 @@ CancellationToken cancellationToken context.WorkerId = workerId; } - var response = await mediator.Send(inputData, tokenHolder.CancellationToken); + var response = await _workerInvokerService.Invoke(scheduledWorker.TaskType, pollResponse.InputData, tokenHolder.CancellationToken); await _taskManager.UpdateAsync( new TaskResult { TaskId = pollResponse.TaskId, Status = TaskResultStatus.COMPLETED, - OutputData = - SerializationHelper.ObjectToDictionary(response, - ConductorConstants.IoJsonSerializerSettings), + OutputData = response, WorkflowInstanceId = pollResponse.WorkflowInstanceId }, tokenHolder.CancellationToken @@ -237,9 +212,7 @@ await _taskManager.UpdateAsync( pollResponse.WorkflowInstanceId ); } - catch (OperationCanceledException) when - (cancellationToken - .IsCancellationRequested) // This is fine since we know cancellationToken comes from background service + catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) // This is fine since we know cancellationToken comes from background service { _logger.LogWarning( "Cancelling task {Task}(id={TaskId}) of workflow {Workflow}(id={WorkflowId}) due to background service shutdown", @@ -273,8 +246,7 @@ await Task.WhenAll( TaskId = pollResponse.TaskId, Status = TaskResultStatus.FAILED, ReasonForIncompletion = exception.Message, - OutputData = SerializationHelper.ObjectToDictionary(errorMessage, - ConductorConstants.IoJsonSerializerSettings), + OutputData = SerializationHelper.ObjectToDictionary(errorMessage, ConductorConstants.IoJsonSerializerSettings), WorkflowInstanceId = pollResponse?.WorkflowInstanceId }, tokenHolder.CancellationToken @@ -286,4 +258,4 @@ await Task.WhenAll( } } } -} \ No newline at end of file +} diff --git a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs index a38f3ebd..bdf840fe 100644 --- a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs +++ b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs @@ -22,15 +22,12 @@ public void NamingUtilShouldReturnCorrectNameableObjectName() public class Request { - public int Counter = 0; - public class Response { } public class Handler : INgWorker { public Task Handle(Request request, CancellationToken cancellationToken) { - request.Counter++; return Task.FromResult(new Response()); } } @@ -44,7 +41,6 @@ public class Middleware : INgWorkerMiddleware CancellationToken cancellationToken ) { - request.Counter++; return await next(request, cancellationToken); } } @@ -59,9 +55,6 @@ public async Task Handle( CancellationToken cancellationToken ) { - var obj = (object)request; - var req = (Request)obj; - req.Counter++; return await next(request, cancellationToken); } } @@ -77,11 +70,12 @@ public async Task Test() var provider = collection.BuildServiceProvider(); var invoker = new WorkerInvokerService(provider); - var sw = Stopwatch.StartNew(); - var @ref = new Request(); - var result = await invoker.Invoke(typeof(Request.Handler), @ref, default); - var response = (Request.Response)result; - var t = sw.ElapsedMilliseconds; + for (int i = 0; i < 5; i++) + { + var sw = Stopwatch.StartNew(); + var result = await invoker.Invoke(typeof(Request.Handler), new Dictionary(), default); + var t = sw.ElapsedMilliseconds; + } } } } From 412c15f5ada6f29bfa0d7d3547c82e8e88ec2d09 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Wed, 25 Jun 2025 01:51:35 +0200 Subject: [PATCH 04/35] Remove IRequest references from code --- .../Handlers/PrepareEmailHandler.cs | 5 ++-- .../Generated/Task.cs | 7 +++--- .../Workflows/CSharpLambdaWorkflow.cs | 3 ++- .../Workflows/SendCustomerNotification.cs | 5 ++-- .../Handlers/EnumTaskHandler.cs | 9 ++++---- .../Handlers/GetCustomerHandler.cs | 6 ++--- .../Handlers/PrepareEmailHandler.cs | 11 +++------ .../Behaviors/ContextLoggingBehavior.cs | 23 ++++++++++--------- .../Behaviors/ErrorHandlingBehavior.cs | 19 ++++++++++----- .../RequestResponseLoggingBehavior.cs | 17 +++++++------- .../TaskExecutionTrackingBehavior.cs | 19 +++++++++------ .../Behaviors/ValidationBehavior.cs | 3 +-- .../Builders/BaseTaskBuilder.cs | 5 ++-- .../Builders/DynamicTaskBuilder.cs | 7 +++--- .../Builders/EventTaskBuilder.cs | 2 +- .../Builders/JsonJqTransformTaskBuilder.cs | 7 +++--- .../Builders/LambdaTaskBuilder.cs | 12 ++++++---- .../Builders/SimpleTaskBuilder.cs | 9 ++++---- .../Builders/SubWorkflowTaskBuilder.cs | 5 ++-- .../Builders/TaskDefinitionBuilder.cs | 10 +------- .../Builders/Workflow.cs | 3 +-- .../Extensions/IPipelineBuilder.cs | 4 ++-- .../Extensions/PipelineBuilder.cs | 3 +-- .../Interface/INgWorker.cs | 7 +++--- .../Interface/INgWorkerMiddleware.cs | 3 +-- .../Interface/ITaskInput.cs | 3 +++ .../Interface/ITaskRequestHandler.cs | 6 ----- .../Model/DecisionTaskModel.cs | 6 ++--- .../Model/DoWhileTaskModel.cs | 6 ++--- .../Model/DynamicForkJoinTaskModel.cs | 6 ++--- .../Model/DynamicTaskModel.cs | 11 ++++----- .../Model/EventTaskModel.cs | 4 ++-- .../Model/HumanTaskModel.cs | 7 +++--- .../Model/JsonJqTransformTaskModel.cs | 5 ++-- .../Model/LambdaTaskModel.cs | 9 ++++---- .../Model/SimpleTaskModel.cs | 3 ++- .../Model/SubWorkflowTaskModel.cs | 3 ++- .../Model/SwitchTaskModel.cs | 6 ++--- src/ConductorSharp.Engine/Model/TaskModel.cs | 2 +- .../Model/TerminateTaskModel.cs | 7 +++--- .../Model/WaitTaskModel.cs | 9 +++----- src/ConductorSharp.Engine/NgWorker.cs | 12 ++++++++++ .../Service/WorkerInvokerService.cs | 13 ++++------- .../TaskRequestHandler.cs | 17 -------------- .../Util/ObjectRequest.cs | 5 ++++ src/ConductorSharp.Engine/Util/WorkerUtil.cs | 14 +++++++++++ .../Builders/CSharpLambdaTaskBuilder.cs | 5 ++-- .../Model/CSharpLambdaTaskModel.cs | 7 +++--- .../Tasks/CSharpLambdaTask.cs | 5 ++-- .../Tasks/ReadWorkflowTasks.cs | 5 ++-- .../Tasks/WaitSeconds.cs | 10 ++++---- .../Integration/UtilityTests.cs | 5 ++-- .../Samples/Tasks/ArrayTask.cs | 14 ++++------- .../Samples/Tasks/CustomerGetV1.cs | 2 +- .../Samples/Tasks/DictionaryInputTask.cs | 2 +- .../Samples/Tasks/EmailPrepareV1.cs | 2 +- .../Samples/Tasks/ListTask.cs | 2 +- .../Samples/Tasks/NestedObjects.cs | 9 ++------ .../Samples/Tasks/TaskPropertiesTask.cs | 6 ++--- .../Samples/Tasks/VersionSubworkflow.cs | 13 ++++------- .../Samples/Workers/GetCustomerHandler.cs | 4 ++-- .../Samples/Workers/PrepareEmailHandler.cs | 4 ++-- .../Samples/Workflows/CSharpLambdaWorkflow.cs | 2 +- .../Samples/Workflows/DynamicTask.cs | 9 ++------ .../Samples/Workflows/EventTaskWorkflow.cs | 2 +- .../Samples/Workflows/StringAddition.cs | 9 ++------ 66 files changed, 222 insertions(+), 253 deletions(-) create mode 100644 src/ConductorSharp.Engine/Interface/ITaskInput.cs delete mode 100644 src/ConductorSharp.Engine/Interface/ITaskRequestHandler.cs create mode 100644 src/ConductorSharp.Engine/NgWorker.cs delete mode 100644 src/ConductorSharp.Engine/TaskRequestHandler.cs create mode 100644 src/ConductorSharp.Engine/Util/ObjectRequest.cs create mode 100644 src/ConductorSharp.Engine/Util/WorkerUtil.cs diff --git a/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs b/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs index 7f4ccda3..1425b456 100644 --- a/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs +++ b/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs @@ -2,11 +2,10 @@ using ConductorSharp.Engine.Builders.Metadata; using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Util; -using MediatR; namespace ConductorSharp.ApiEnabled.Handlers; -public class PrepareEmailRequest : IRequest +public class PrepareEmailRequest : ITaskInput { public string CustomerName { get; set; } public string Address { get; set; } @@ -18,7 +17,7 @@ public class PrepareEmailResponse } [OriginalName("EMAIL_prepare")] -public class PrepareEmailHandler : ITaskRequestHandler +public class PrepareEmailHandler : INgWorker { private readonly ConductorSharpExecutionContext _context; private readonly ILogger _logger; diff --git a/examples/ConductorSharp.Definitions/Generated/Task.cs b/examples/ConductorSharp.Definitions/Generated/Task.cs index 6974656d..d9dae6e5 100644 --- a/examples/ConductorSharp.Definitions/Generated/Task.cs +++ b/examples/ConductorSharp.Definitions/Generated/Task.cs @@ -1,4 +1,5 @@ using ConductorSharp.Engine.Builders.Metadata; +using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; using ConductorSharp.Engine.Util; using MediatR; @@ -6,7 +7,7 @@ namespace ConductorSharp.Definitions.Generated { - public partial class EmailPrepareV1Input : IRequest + public partial class EmailPrepareV1Input : ITaskInput { /// /// address @@ -33,7 +34,7 @@ public partial class EmailPrepareV1Output [OriginalName("EMAIL_prepare")] public partial class EmailPrepareV1 : SimpleTaskModel { } - public partial class CustomerGetV1Input : IRequest + public partial class CustomerGetV1Input : ITaskInput { /// /// customer_id @@ -61,7 +62,7 @@ public partial class CustomerGetV1Output [OriginalName("CUSTOMER_get")] public partial class CustomerGetV1 : SimpleTaskModel { } - public partial class EnumTaskInput : IRequest + public partial class EnumTaskInput : ITaskInput { /// /// status diff --git a/examples/ConductorSharp.Definitions/Workflows/CSharpLambdaWorkflow.cs b/examples/ConductorSharp.Definitions/Workflows/CSharpLambdaWorkflow.cs index 4a75b830..f7e8b605 100644 --- a/examples/ConductorSharp.Definitions/Workflows/CSharpLambdaWorkflow.cs +++ b/examples/ConductorSharp.Definitions/Workflows/CSharpLambdaWorkflow.cs @@ -1,5 +1,6 @@ using ConductorSharp.Engine.Builders; using ConductorSharp.Engine.Builders.Metadata; +using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; using ConductorSharp.Patterns.Builders; using ConductorSharp.Patterns.Model; @@ -18,7 +19,7 @@ public class CSharpLambdaWorkflowOutput : WorkflowOutput { } [WorkflowMetadata(OwnerEmail = "test@test.com")] public class CSharpLambdaWorkflow : Workflow { - public class LambdaTaskInput : IRequest + public class LambdaTaskInput : ITaskInput { public string LambdaInput { get; set; } } diff --git a/examples/ConductorSharp.Definitions/Workflows/SendCustomerNotification.cs b/examples/ConductorSharp.Definitions/Workflows/SendCustomerNotification.cs index d21f78d9..cf207672 100644 --- a/examples/ConductorSharp.Definitions/Workflows/SendCustomerNotification.cs +++ b/examples/ConductorSharp.Definitions/Workflows/SendCustomerNotification.cs @@ -1,10 +1,9 @@ using ConductorSharp.Definitions.Generated; using ConductorSharp.Engine.Builders; using ConductorSharp.Engine.Builders.Metadata; +using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; -using ConductorSharp.Engine.Util; using ConductorSharp.Patterns.Tasks; -using MediatR; namespace ConductorSharp.Definitions.Workflows { @@ -21,7 +20,7 @@ public class SendCustomerNotificationOutput : WorkflowOutput public object Constant { get; set; } } - public class ExpectedDynamicInput : CustomerGetV1Input, IRequest { } + public class ExpectedDynamicInput : CustomerGetV1Input, ITaskInput { } public class ExpectedDynamicOutput : CustomerGetV1Output { } diff --git a/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs b/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs index 6f14bf63..198dd2a3 100644 --- a/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs +++ b/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs @@ -1,11 +1,10 @@ using ConductorSharp.Client.Generated; -using ConductorSharp.Engine; using ConductorSharp.Engine.Builders.Metadata; -using MediatR; +using ConductorSharp.Engine.Interface; namespace ConductorSharp.NoApi.Handlers { - public class EnumTaskInput : IRequest + public class EnumTaskInput : ITaskInput { public WorkflowStatus Status { get; set; } } @@ -16,9 +15,9 @@ public class EnumTaskOutput } [OriginalName("ENUM_task")] - public class EnumTaskHandler : TaskRequestHandler + public class EnumTaskHandler : INgWorker { - public override Task Handle(EnumTaskInput request, CancellationToken cancellationToken) + public Task Handle(EnumTaskInput request, CancellationToken cancellationToken) { Console.WriteLine(request.Status); return System.Threading.Tasks.Task.FromResult(new EnumTaskOutput() { Status = request.Status }); diff --git a/examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs b/examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs index b1531eed..e713c643 100644 --- a/examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs +++ b/examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs @@ -1,12 +1,10 @@ using System.ComponentModel.DataAnnotations; using ConductorSharp.Engine.Builders.Metadata; using ConductorSharp.Engine.Interface; -using ConductorSharp.Engine.Util; -using MediatR; namespace ConductorSharp.NoApi.Handlers; -public class GetCustomerRequest : IRequest +public class GetCustomerRequest : ITaskInput { [Required] public int CustomerId { get; set; } @@ -26,7 +24,7 @@ public class Customer } [OriginalName("CUSTOMER_get")] -public class GetCustomerHandler : ITaskRequestHandler +public class GetCustomerHandler : INgWorker { private static Customer[] customers = new Customer[] { diff --git a/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs b/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs index d3b31d66..cf258ab2 100644 --- a/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs +++ b/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs @@ -1,17 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Text; using ConductorSharp.Engine.Builders.Metadata; using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Util; -using MediatR; using Microsoft.Extensions.Logging; namespace ConductorSharp.NoApi.Handlers { - public class PrepareEmailRequest : IRequest + public class PrepareEmailRequest : ITaskInput { public string CustomerName { get; set; } public string Address { get; set; } @@ -23,7 +18,7 @@ public class PrepareEmailResponse } [OriginalName("EMAIL_prepare")] - public class PrepareEmailHandler : ITaskRequestHandler + public class PrepareEmailHandler : INgWorker { private readonly ConductorSharpExecutionContext _context; private readonly ILogger _logger; diff --git a/src/ConductorSharp.Engine/Behaviors/ContextLoggingBehavior.cs b/src/ConductorSharp.Engine/Behaviors/ContextLoggingBehavior.cs index fde9a5d6..4872ac3d 100644 --- a/src/ConductorSharp.Engine/Behaviors/ContextLoggingBehavior.cs +++ b/src/ConductorSharp.Engine/Behaviors/ContextLoggingBehavior.cs @@ -1,17 +1,14 @@ -using ConductorSharp.Engine.Util; -using MediatR; -using Microsoft.Extensions.Logging; -using Serilog.Context; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; +using System; using System.Threading; using System.Threading.Tasks; +using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; +using Serilog.Context; namespace ConductorSharp.Engine.Behaviors { - public class ContextLoggingBehavior : IPipelineBehavior where TRequest : IRequest + public class ContextLoggingBehavior : INgWorkerMiddleware + where TRequest : class, ITaskInput, new() { private readonly ConductorSharpExecutionContext _executionContext; private const string LoggerPropertyName = "ConductorContext"; @@ -21,10 +18,14 @@ public ContextLoggingBehavior(ConductorSharpExecutionContext executionContext) _executionContext = executionContext; } - public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) + public async Task Handle( + TRequest request, + Func> next, + CancellationToken cancellationToken + ) { using var _ = LogContext.PushProperty(LoggerPropertyName, _executionContext, true); - return await next(); + return await next(request, cancellationToken); } } } diff --git a/src/ConductorSharp.Engine/Behaviors/ErrorHandlingBehavior.cs b/src/ConductorSharp.Engine/Behaviors/ErrorHandlingBehavior.cs index 82fbcf2a..2036cbe0 100644 --- a/src/ConductorSharp.Engine/Behaviors/ErrorHandlingBehavior.cs +++ b/src/ConductorSharp.Engine/Behaviors/ErrorHandlingBehavior.cs @@ -1,18 +1,25 @@ -using ConductorSharp.Engine.Exceptions; -using MediatR; -using System; +using System; using System.Threading; using System.Threading.Tasks; +using ConductorSharp.Engine.Exceptions; +using ConductorSharp.Engine.Interface; +using MediatR; namespace ConductorSharp.Engine.Behaviors { - public class ErrorHandlingBehavior : IPipelineBehavior where TRequest : IRequest + // TODO: Consider removing + public class ErrorHandlingBehavior : INgWorkerMiddleware + where TRequest : class, ITaskInput, new() { - public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) + public async Task Handle( + TRequest request, + Func> next, + CancellationToken cancellationToken + ) { try { - return await next(); + return await next(request, cancellationToken); } catch (Exception ex) { diff --git a/src/ConductorSharp.Engine/Behaviors/RequestResponseLoggingBehavior.cs b/src/ConductorSharp.Engine/Behaviors/RequestResponseLoggingBehavior.cs index 1cd81959..f7d7ce27 100644 --- a/src/ConductorSharp.Engine/Behaviors/RequestResponseLoggingBehavior.cs +++ b/src/ConductorSharp.Engine/Behaviors/RequestResponseLoggingBehavior.cs @@ -1,19 +1,16 @@ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Text; using System.Threading; using System.Threading.Tasks; +using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Util; -using MediatR; using Microsoft.Extensions.Logging; -using Serilog.Context; namespace ConductorSharp.Engine.Behaviors { // TODO: Consider removing this - public class RequestResponseLoggingBehavior : IPipelineBehavior - where TRequest : IRequest + public class RequestResponseLoggingBehavior : INgWorkerMiddleware + where TRequest : class, ITaskInput, new() { private readonly ILogger> _logger; private readonly ConductorSharpExecutionContext _context; @@ -27,7 +24,11 @@ ConductorSharpExecutionContext context _context = context; } - public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) + public async Task Handle( + TRequest request, + Func> next, + CancellationToken cancellationToken + ) { var requestId = Guid.NewGuid(); var requestName = typeof(TRequest).Name; @@ -44,7 +45,7 @@ public async Task Handle(TRequest request, RequestHandlerDelegate : IPipelineBehavior where TRequest : IRequest + public class TaskExecutionTrackingBehavior : INgWorkerMiddleware + where TRequest : class, ITaskInput, new() { private readonly ConductorSharpExecutionContext _executionContext; private readonly IEnumerable _taskExecutionServices; @@ -23,7 +24,11 @@ IEnumerable taskExecutionServices _taskExecutionServices = taskExecutionServices; } - public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) + public async Task Handle( + TRequest request, + Func> next, + CancellationToken cancellationToken + ) { var trackedTask = new RunningTask { @@ -39,7 +44,7 @@ public async Task Handle(TRequest request, RequestHandlerDelegate : INgWorkerMiddleware - where TRequest : class, new() - where TResponse : class, new() + where TRequest : class, ITaskInput, new() { public async Task Handle( TRequest request, diff --git a/src/ConductorSharp.Engine/Builders/BaseTaskBuilder.cs b/src/ConductorSharp.Engine/Builders/BaseTaskBuilder.cs index dc300494..98f6e00a 100644 --- a/src/ConductorSharp.Engine/Builders/BaseTaskBuilder.cs +++ b/src/ConductorSharp.Engine/Builders/BaseTaskBuilder.cs @@ -4,13 +4,12 @@ using ConductorSharp.Engine.Model; using ConductorSharp.Engine.Util; using ConductorSharp.Engine.Util.Builders; -using MediatR; using Newtonsoft.Json.Linq; namespace ConductorSharp.Engine.Builders { - public abstract class BaseTaskBuilder : ITaskOptionsBuilder, ITaskBuilder - where A : IRequest + public abstract class BaseTaskBuilder : ITaskOptionsBuilder, ITaskBuilder + where TInput : ITaskInput { protected readonly JObject _inputParameters; protected readonly string _taskRefferenceName; diff --git a/src/ConductorSharp.Engine/Builders/DynamicTaskBuilder.cs b/src/ConductorSharp.Engine/Builders/DynamicTaskBuilder.cs index 4616820a..5765904c 100644 --- a/src/ConductorSharp.Engine/Builders/DynamicTaskBuilder.cs +++ b/src/ConductorSharp.Engine/Builders/DynamicTaskBuilder.cs @@ -5,7 +5,6 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; using ConductorSharp.Engine.Util.Builders; -using MediatR; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -19,7 +18,7 @@ public static ITaskOptionsBuilder AddTask( Expression>> input ) where TWorkflow : ITypedWorkflow - where TInput : IRequest + where TInput : ITaskInput { var taskBuilder = new DynamicTaskBuilder(reference.Body, input.Body, builder.BuildConfiguration); builder.AddTaskBuilderToSequence(taskBuilder); @@ -27,8 +26,8 @@ Expression>> input } } - public class DynamicTaskBuilder(Expression taskExpression, Expression inputExpression, BuildConfiguration buildConfiguration) - : BaseTaskBuilder, O>(taskExpression, inputExpression, buildConfiguration) + public class DynamicTaskBuilder(Expression taskExpression, Expression inputExpression, BuildConfiguration buildConfiguration) + : BaseTaskBuilder, TOutput>(taskExpression, inputExpression, buildConfiguration) { private const string DynamicTasknameParam = "task_to_execute"; diff --git a/src/ConductorSharp.Engine/Builders/EventTaskBuilder.cs b/src/ConductorSharp.Engine/Builders/EventTaskBuilder.cs index cc7f3334..83c8d092 100644 --- a/src/ConductorSharp.Engine/Builders/EventTaskBuilder.cs +++ b/src/ConductorSharp.Engine/Builders/EventTaskBuilder.cs @@ -18,7 +18,7 @@ public static ITaskOptionsBuilder AddTask( string sink ) where TWorkflow : ITypedWorkflow - where TInput : IRequest + where TInput : ITaskInput { var taskBuilder = new EventTaskBuilder(reference.Body, input.Body, builder.BuildConfiguration, sink); builder.AddTaskBuilderToSequence(taskBuilder); diff --git a/src/ConductorSharp.Engine/Builders/JsonJqTransformTaskBuilder.cs b/src/ConductorSharp.Engine/Builders/JsonJqTransformTaskBuilder.cs index 64bebbf6..f328e9f4 100644 --- a/src/ConductorSharp.Engine/Builders/JsonJqTransformTaskBuilder.cs +++ b/src/ConductorSharp.Engine/Builders/JsonJqTransformTaskBuilder.cs @@ -5,7 +5,6 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; using ConductorSharp.Engine.Util.Builders; -using MediatR; namespace ConductorSharp.Engine.Builders { @@ -17,7 +16,7 @@ public static ITaskOptionsBuilder AddTask( Expression> input ) where TWorkflow : ITypedWorkflow - where TInput : IRequest + where TInput : ITaskInput { var taskBuilder = new JsonJqTransformTaskBuilder(refference.Body, input.Body, builder.BuildConfiguration); builder.AddTaskBuilderToSequence(taskBuilder); @@ -25,8 +24,8 @@ Expression> input } } - public class JsonJqTransformTaskBuilder : BaseTaskBuilder - where A : IRequest + public class JsonJqTransformTaskBuilder : BaseTaskBuilder + where TInput : ITaskInput { public JsonJqTransformTaskBuilder(Expression taskExpression, Expression inputExpression, BuildConfiguration buildConfiguration) : base(taskExpression, inputExpression, buildConfiguration) diff --git a/src/ConductorSharp.Engine/Builders/LambdaTaskBuilder.cs b/src/ConductorSharp.Engine/Builders/LambdaTaskBuilder.cs index f38b0915..9533f860 100644 --- a/src/ConductorSharp.Engine/Builders/LambdaTaskBuilder.cs +++ b/src/ConductorSharp.Engine/Builders/LambdaTaskBuilder.cs @@ -19,7 +19,7 @@ public static ITaskOptionsBuilder AddTask( string script ) where TWorkflow : ITypedWorkflow - where TInput : IRequest + where TInput : ITaskInput { var taskBuilder = new LambdaTaskBuilder(script, referrence.Body, input.Body, builder.BuildConfiguration); @@ -28,9 +28,13 @@ string script } } - public class LambdaTaskBuilder(string script, Expression taskExpression, Expression inputExpression, BuildConfiguration buildConfiguration) - : BaseTaskBuilder(taskExpression, inputExpression, buildConfiguration) - where A : IRequest + public class LambdaTaskBuilder( + string script, + Expression taskExpression, + Expression inputExpression, + BuildConfiguration buildConfiguration + ) : BaseTaskBuilder(taskExpression, inputExpression, buildConfiguration) + where TInput : ITaskInput { private readonly string _script = script; diff --git a/src/ConductorSharp.Engine/Builders/SimpleTaskBuilder.cs b/src/ConductorSharp.Engine/Builders/SimpleTaskBuilder.cs index de685ed4..7f6533fa 100644 --- a/src/ConductorSharp.Engine/Builders/SimpleTaskBuilder.cs +++ b/src/ConductorSharp.Engine/Builders/SimpleTaskBuilder.cs @@ -5,7 +5,6 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; using ConductorSharp.Engine.Util.Builders; -using MediatR; namespace ConductorSharp.Engine.Builders { @@ -17,7 +16,7 @@ public static ITaskOptionsBuilder AddTask( Expression> input ) where TWorkflow : ITypedWorkflow - where Tinput : IRequest + where Tinput : ITaskInput { var taskBuilder = new SimpleTaskBuilder(refference.Body, input.Body, builder.BuildConfiguration); builder.AddTaskBuilderToSequence(taskBuilder); @@ -25,9 +24,9 @@ Expression> input } } - public class SimpleTaskBuilder(Expression taskExpression, Expression inputExpression, BuildConfiguration buildConfiguration) - : BaseTaskBuilder(taskExpression, inputExpression, buildConfiguration) - where A : IRequest + public class SimpleTaskBuilder(Expression taskExpression, Expression inputExpression, BuildConfiguration buildConfiguration) + : BaseTaskBuilder(taskExpression, inputExpression, buildConfiguration) + where TInput : ITaskInput { public override WorkflowTask[] Build() => [ diff --git a/src/ConductorSharp.Engine/Builders/SubWorkflowTaskBuilder.cs b/src/ConductorSharp.Engine/Builders/SubWorkflowTaskBuilder.cs index 2fded7eb..6852e7e7 100644 --- a/src/ConductorSharp.Engine/Builders/SubWorkflowTaskBuilder.cs +++ b/src/ConductorSharp.Engine/Builders/SubWorkflowTaskBuilder.cs @@ -8,7 +8,6 @@ using ConductorSharp.Engine.Model; using ConductorSharp.Engine.Util; using ConductorSharp.Engine.Util.Builders; -using MediatR; namespace ConductorSharp.Engine.Builders { @@ -20,7 +19,7 @@ public static ITaskOptionsBuilder AddTask( Expression> input ) where TWorkflow : ITypedWorkflow - where TInput : IRequest + where TInput : ITaskInput { var taskBuilder = new SubWorkflowTaskBuilder(referrence.Body, input.Body, builder.BuildConfiguration); builder.AddTaskBuilderToSequence(taskBuilder); @@ -30,7 +29,7 @@ Expression> input public class SubWorkflowTaskBuilder(Expression taskExpression, Expression inputExpression, BuildConfiguration buildConfiguration) : BaseTaskBuilder(taskExpression, inputExpression, buildConfiguration) - where TInput : IRequest + where TInput : ITaskInput { private readonly int _version = GetVersion(taskExpression); diff --git a/src/ConductorSharp.Engine/Builders/TaskDefinitionBuilder.cs b/src/ConductorSharp.Engine/Builders/TaskDefinitionBuilder.cs index ee1a6965..b657246e 100644 --- a/src/ConductorSharp.Engine/Builders/TaskDefinitionBuilder.cs +++ b/src/ConductorSharp.Engine/Builders/TaskDefinitionBuilder.cs @@ -22,15 +22,7 @@ public TaskDef Build(Type taskType, Action updateOptions updateOptions?.Invoke(options); - var interfaces = taskType - .GetInterfaces() - .Where(a => a.IsGenericType && a.GetGenericTypeDefinition() == typeof(ITaskRequestHandler<,>)) - .First(); - - var genericArguments = interfaces.GetGenericArguments(); - - var inputType = genericArguments[0]; - var outputType = genericArguments[1]; + var (inputType, outputType) = WorkerUtil.GetRequestResponseTypes(taskType); var originalName = _taskNameBuilder.Build(taskType); diff --git a/src/ConductorSharp.Engine/Builders/Workflow.cs b/src/ConductorSharp.Engine/Builders/Workflow.cs index 1be1cdd0..b2e50b59 100644 --- a/src/ConductorSharp.Engine/Builders/Workflow.cs +++ b/src/ConductorSharp.Engine/Builders/Workflow.cs @@ -1,11 +1,10 @@ using ConductorSharp.Client.Generated; using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; -using MediatR; namespace ConductorSharp.Engine.Builders { - public class WorkflowInput : IWorkflowInput, IRequest + public class WorkflowInput : IWorkflowInput, ITaskInput where T : WorkflowOutput { } public class WorkflowOutput { } diff --git a/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs index 9430cce5..8cdda617 100644 --- a/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs @@ -10,9 +10,9 @@ public interface IPipelineBuilder void AddContextLogging(); void AddExecutionTaskTracking(); void AddCustomBehavior(Type behaviorType); + void AddCustomBehavior() where TWorkerMiddleware : class, INgWorkerMiddleware - where TRequest : class, new() - where TResponse : class, new(); + where TRequest : class, ITaskInput, new(); } } diff --git a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs index a846cfd3..59a730b8 100644 --- a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs @@ -21,8 +21,7 @@ public void AddExecutionTaskTracking() => public void AddCustomBehavior() where TWorkerMiddleware : class, INgWorkerMiddleware - where TRequest : class, new() - where TResponse : class, new() + where TRequest : class, ITaskInput, new() { serviceCollection.AddTransient, TWorkerMiddleware>(); } diff --git a/src/ConductorSharp.Engine/Interface/INgWorker.cs b/src/ConductorSharp.Engine/Interface/INgWorker.cs index e51a7b0f..8d8ab82c 100644 --- a/src/ConductorSharp.Engine/Interface/INgWorker.cs +++ b/src/ConductorSharp.Engine/Interface/INgWorker.cs @@ -1,11 +1,12 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; +using ConductorSharp.Engine.Util; namespace ConductorSharp.Engine.Interface; public interface INgWorker - where TRequest : class, new() - where TResponse : new() + where TRequest : class, ITaskInput, new() { Task Handle(TRequest test, CancellationToken cancellationToken); } diff --git a/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs b/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs index 8849ff97..6032b6d8 100644 --- a/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs +++ b/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs @@ -5,8 +5,7 @@ namespace ConductorSharp.Engine.Interface; public interface INgWorkerMiddleware - where TRequest : class, new() - where TResponse : class, new() + where TRequest : class, ITaskInput, new() { Task Handle(TRequest request, Func> next, CancellationToken cancellationToken); } diff --git a/src/ConductorSharp.Engine/Interface/ITaskInput.cs b/src/ConductorSharp.Engine/Interface/ITaskInput.cs new file mode 100644 index 00000000..6e668049 --- /dev/null +++ b/src/ConductorSharp.Engine/Interface/ITaskInput.cs @@ -0,0 +1,3 @@ +namespace ConductorSharp.Engine.Interface; + +public interface ITaskInput { } diff --git a/src/ConductorSharp.Engine/Interface/ITaskRequestHandler.cs b/src/ConductorSharp.Engine/Interface/ITaskRequestHandler.cs deleted file mode 100644 index 15e0516a..00000000 --- a/src/ConductorSharp.Engine/Interface/ITaskRequestHandler.cs +++ /dev/null @@ -1,6 +0,0 @@ -using MediatR; - -namespace ConductorSharp.Engine.Interface -{ - public interface ITaskRequestHandler : IWorker, IRequestHandler where TRequest : IRequest { } -} diff --git a/src/ConductorSharp.Engine/Model/DecisionTaskModel.cs b/src/ConductorSharp.Engine/Model/DecisionTaskModel.cs index 49fe4f8f..d06e19e5 100644 --- a/src/ConductorSharp.Engine/Model/DecisionTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/DecisionTaskModel.cs @@ -1,11 +1,11 @@ -using MediatR; +using ConductorSharp.Engine.Interface; namespace ConductorSharp.Engine.Model { - public class DecisionTaskInput : IRequest + public class DecisionTaskInput : ITaskInput { public object CaseValueParam { get; set; } } - public class DecisionTaskModel : TaskModel { } + public class DecisionTaskModel : TaskModel; } diff --git a/src/ConductorSharp.Engine/Model/DoWhileTaskModel.cs b/src/ConductorSharp.Engine/Model/DoWhileTaskModel.cs index f635ae2b..b6c559e2 100644 --- a/src/ConductorSharp.Engine/Model/DoWhileTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/DoWhileTaskModel.cs @@ -1,12 +1,12 @@ using ConductorSharp.Engine.Builders; -using MediatR; +using ConductorSharp.Engine.Interface; namespace ConductorSharp.Engine.Model { /// /// Input for configuration of the DO_WHILE task. /// - public class DoWhileInput : IRequest, IWorkflowInput + public class DoWhileInput : ITaskInput, IWorkflowInput { public object Value { get; set; } = null; } @@ -14,5 +14,5 @@ public class DoWhileInput : IRequest, IWorkflowInput /// /// Task Model to reference the do while task in the workflow builders /// - public class DoWhileTaskModel : TaskModel { } + public class DoWhileTaskModel : TaskModel; } diff --git a/src/ConductorSharp.Engine/Model/DynamicForkJoinTaskModel.cs b/src/ConductorSharp.Engine/Model/DynamicForkJoinTaskModel.cs index a8e14a76..87474900 100644 --- a/src/ConductorSharp.Engine/Model/DynamicForkJoinTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/DynamicForkJoinTaskModel.cs @@ -1,13 +1,13 @@ -using MediatR; +using ConductorSharp.Engine.Interface; namespace ConductorSharp.Engine.Model { - public class DynamicForkJoinInput : IRequest + public class DynamicForkJoinInput : ITaskInput { public object DynamicTasks { get; set; } public object DynamicTasksI { get; set; } } - public class DynamicForkJoinTaskModel : TaskModel { } + public class DynamicForkJoinTaskModel : TaskModel; } diff --git a/src/ConductorSharp.Engine/Model/DynamicTaskModel.cs b/src/ConductorSharp.Engine/Model/DynamicTaskModel.cs index ba50a2e1..bf740f90 100644 --- a/src/ConductorSharp.Engine/Model/DynamicTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/DynamicTaskModel.cs @@ -1,15 +1,12 @@ -using MediatR; -using System; -using System.Collections.Generic; -using System.Text; +using ConductorSharp.Engine.Interface; namespace ConductorSharp.Engine.Model { - public class DynamicTaskInput : IRequest + public class DynamicTaskInput : ITaskInput { - public I TaskInput { get; set; } + public TInput TaskInput { get; set; } public string TaskToExecute { get; set; } } - public class DynamicTaskModel : TaskModel, O> { } + public class DynamicTaskModel : TaskModel, TOutput>; } diff --git a/src/ConductorSharp.Engine/Model/EventTaskModel.cs b/src/ConductorSharp.Engine/Model/EventTaskModel.cs index ee25faab..63d64a7c 100644 --- a/src/ConductorSharp.Engine/Model/EventTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/EventTaskModel.cs @@ -1,4 +1,4 @@ -using MediatR; +using ConductorSharp.Engine.Interface; using Newtonsoft.Json; namespace ConductorSharp.Engine.Model; @@ -28,4 +28,4 @@ public class EventTaskModelOutput } public class EventTaskModel : TaskModel - where TInput : IRequest { } + where TInput : ITaskInput; diff --git a/src/ConductorSharp.Engine/Model/HumanTaskModel.cs b/src/ConductorSharp.Engine/Model/HumanTaskModel.cs index 1e6dbeb6..eb50f196 100644 --- a/src/ConductorSharp.Engine/Model/HumanTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/HumanTaskModel.cs @@ -1,9 +1,8 @@ -using MediatR; -using Newtonsoft.Json; +using ConductorSharp.Engine.Interface; namespace ConductorSharp.Engine.Model { - public class HumanTaskInput : IRequest { } + public class HumanTaskInput : ITaskInput; - public class HumanTaskModel : TaskModel, TOutput> { } + public class HumanTaskModel : TaskModel, TOutput>; } diff --git a/src/ConductorSharp.Engine/Model/JsonJqTransformTaskModel.cs b/src/ConductorSharp.Engine/Model/JsonJqTransformTaskModel.cs index c3ba9feb..ecd1a33f 100644 --- a/src/ConductorSharp.Engine/Model/JsonJqTransformTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/JsonJqTransformTaskModel.cs @@ -1,6 +1,7 @@ -using MediatR; +using ConductorSharp.Engine.Interface; namespace ConductorSharp.Engine.Model { - public class JsonJqTransformTaskModel : TaskModel where I : IRequest { } + public class JsonJqTransformTaskModel : TaskModel + where TInput : ITaskInput; } diff --git a/src/ConductorSharp.Engine/Model/LambdaTaskModel.cs b/src/ConductorSharp.Engine/Model/LambdaTaskModel.cs index 61016e3e..7ab9c50e 100644 --- a/src/ConductorSharp.Engine/Model/LambdaTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/LambdaTaskModel.cs @@ -1,4 +1,4 @@ -using MediatR; +using ConductorSharp.Engine.Interface; namespace ConductorSharp.Engine.Model { @@ -7,9 +7,10 @@ public abstract class LambdaOutputModel public O Result { get; set; } } - public abstract class LambdaTaskModel where I : IRequest + public abstract class LambdaTaskModel + where TInput : ITaskInput { - public I Input { get; set; } - public LambdaOutputModel Output { get; set; } + public TInput Input { get; set; } + public LambdaOutputModel Output { get; set; } } } diff --git a/src/ConductorSharp.Engine/Model/SimpleTaskModel.cs b/src/ConductorSharp.Engine/Model/SimpleTaskModel.cs index 3bf5192c..f399103a 100644 --- a/src/ConductorSharp.Engine/Model/SimpleTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/SimpleTaskModel.cs @@ -3,5 +3,6 @@ namespace ConductorSharp.Engine.Model { - public abstract class SimpleTaskModel : TaskModel, INameable where I : IRequest { } + public abstract class SimpleTaskModel : TaskModel, INameable + where TInput : ITaskInput; } diff --git a/src/ConductorSharp.Engine/Model/SubWorkflowTaskModel.cs b/src/ConductorSharp.Engine/Model/SubWorkflowTaskModel.cs index 122a1942..5b0db52f 100644 --- a/src/ConductorSharp.Engine/Model/SubWorkflowTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/SubWorkflowTaskModel.cs @@ -3,5 +3,6 @@ namespace ConductorSharp.Engine.Model { - public abstract class SubWorkflowTaskModel : TaskModel, INameable where I : IRequest { } + public abstract class SubWorkflowTaskModel : TaskModel, INameable + where TInput : ITaskInput; } diff --git a/src/ConductorSharp.Engine/Model/SwitchTaskModel.cs b/src/ConductorSharp.Engine/Model/SwitchTaskModel.cs index e0c391c2..a923b010 100644 --- a/src/ConductorSharp.Engine/Model/SwitchTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/SwitchTaskModel.cs @@ -1,11 +1,11 @@ -using MediatR; +using ConductorSharp.Engine.Interface; namespace ConductorSharp.Engine.Model { - public class SwitchTaskInput : IRequest + public class SwitchTaskInput : ITaskInput { public object SwitchCaseValue { get; set; } } - public class SwitchTaskModel : TaskModel { } + public class SwitchTaskModel : TaskModel; } diff --git a/src/ConductorSharp.Engine/Model/TaskModel.cs b/src/ConductorSharp.Engine/Model/TaskModel.cs index 1fd31266..ff919ecd 100644 --- a/src/ConductorSharp.Engine/Model/TaskModel.cs +++ b/src/ConductorSharp.Engine/Model/TaskModel.cs @@ -4,7 +4,7 @@ namespace ConductorSharp.Engine.Model { - public abstract class TaskModel : ITaskModel where I : IRequest + public abstract class TaskModel : ITaskModel { public I Input { get; } diff --git a/src/ConductorSharp.Engine/Model/TerminateTaskModel.cs b/src/ConductorSharp.Engine/Model/TerminateTaskModel.cs index 18ce1fb5..2deb0c6e 100644 --- a/src/ConductorSharp.Engine/Model/TerminateTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/TerminateTaskModel.cs @@ -1,4 +1,5 @@ -using ConductorSharp.Engine.Util; +using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; using MediatR; using Newtonsoft.Json; @@ -13,7 +14,7 @@ public enum TerminationStatus Failed }; - public class TerminateTaskInput : IRequest + public class TerminateTaskInput : ITaskInput { [JsonProperty("workflowOutput")] public object WorkflowOutput { get; set; } @@ -22,5 +23,5 @@ public class TerminateTaskInput : IRequest public TerminationStatus TerminationStatus { get; set; } } - public class TerminateTaskModel : TaskModel { } + public class TerminateTaskModel : TaskModel; } diff --git a/src/ConductorSharp.Engine/Model/WaitTaskModel.cs b/src/ConductorSharp.Engine/Model/WaitTaskModel.cs index 37b66355..0919f74e 100644 --- a/src/ConductorSharp.Engine/Model/WaitTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/WaitTaskModel.cs @@ -1,12 +1,9 @@ -using MediatR; +using ConductorSharp.Engine.Interface; using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Text; namespace ConductorSharp.Engine.Model { - public class WaitTaskInput : IRequest + public class WaitTaskInput : ITaskInput { [JsonProperty("duration")] public string Duration { get; set; } @@ -15,5 +12,5 @@ public class WaitTaskInput : IRequest public string Until { get; set; } } - public class WaitTaskModel : TaskModel { } + public class WaitTaskModel : TaskModel; } diff --git a/src/ConductorSharp.Engine/NgWorker.cs b/src/ConductorSharp.Engine/NgWorker.cs new file mode 100644 index 00000000..0182c512 --- /dev/null +++ b/src/ConductorSharp.Engine/NgWorker.cs @@ -0,0 +1,12 @@ +using System.Threading; +using System.Threading.Tasks; +using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Model; + +namespace ConductorSharp.Engine; + +public abstract class NgWorker : SimpleTaskModel, INgWorker + where TRequest : class, ITaskInput, new() +{ + public abstract Task Handle(TRequest test, CancellationToken cancellationToken); +} diff --git a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs index 8f945283..9c9c350e 100644 --- a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs +++ b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs @@ -12,6 +12,7 @@ using ConductorSharp.Client; using ConductorSharp.Client.Util; using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; using Microsoft.Extensions.DependencyInjection; namespace ConductorSharp.Engine.Service @@ -23,12 +24,12 @@ private record WorkerTypeInfo public WorkerTypeInfo(Type workerType) { WorkerType = workerType; - (RequestType, ResponseType) = GetRequestResponseTypes(workerType); + (RequestType, ResponseType) = WorkerUtil.GetRequestResponseTypes(workerType); MiddlewareType = typeof(INgWorkerMiddleware<,>).MakeGenericType(RequestType, ResponseType); WorkerHandleMethod = typeof(INgWorker<,>) .MakeGenericType(RequestType, ResponseType) - .GetMethod(nameof(INgWorker.Handle)); - MiddlewareHandleMethod = MiddlewareType.GetMethod(nameof(INgWorkerMiddleware.Handle)); + .GetMethod(nameof(INgWorker.Handle)); + MiddlewareHandleMethod = MiddlewareType.GetMethod(nameof(INgWorkerMiddleware.Handle)); NextFuncType = MiddlewareHandleMethod!.GetParameters().FirstOrDefault(p => p.Name == "next")!.ParameterType; TaskResultProperty = typeof(Task<>).MakeGenericType(ResponseType).GetProperty(nameof(Task.Result)); } @@ -41,12 +42,6 @@ public WorkerTypeInfo(Type workerType) public MethodInfo MiddlewareHandleMethod { get; } public Type NextFuncType { get; } public PropertyInfo TaskResultProperty { get; } - - private static (Type RequestType, Type ResponseType) GetRequestResponseTypes(Type workerType) - { - var types = workerType.GetInterface(typeof(INgWorker<,>).Name)!.GetGenericArguments(); - return (types[0], types[1]); - } } private readonly IServiceProvider _serviceProvider = serviceProvider; diff --git a/src/ConductorSharp.Engine/TaskRequestHandler.cs b/src/ConductorSharp.Engine/TaskRequestHandler.cs deleted file mode 100644 index daf1fa95..00000000 --- a/src/ConductorSharp.Engine/TaskRequestHandler.cs +++ /dev/null @@ -1,17 +0,0 @@ -using ConductorSharp.Engine.Interface; -using ConductorSharp.Engine.Model; -using MediatR; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace ConductorSharp.Engine -{ - public abstract class TaskRequestHandler : SimpleTaskModel, ITaskRequestHandler - where TInput : IRequest - { - public abstract Task Handle(TInput request, CancellationToken cancellationToken); - } -} diff --git a/src/ConductorSharp.Engine/Util/ObjectRequest.cs b/src/ConductorSharp.Engine/Util/ObjectRequest.cs new file mode 100644 index 00000000..93ea0f6a --- /dev/null +++ b/src/ConductorSharp.Engine/Util/ObjectRequest.cs @@ -0,0 +1,5 @@ +using ConductorSharp.Engine.Interface; + +namespace ConductorSharp.Engine.Util; + +internal class ObjectRequest : ITaskInput; diff --git a/src/ConductorSharp.Engine/Util/WorkerUtil.cs b/src/ConductorSharp.Engine/Util/WorkerUtil.cs new file mode 100644 index 00000000..68dc755d --- /dev/null +++ b/src/ConductorSharp.Engine/Util/WorkerUtil.cs @@ -0,0 +1,14 @@ +using System; +using ConductorSharp.Engine.Interface; + +namespace ConductorSharp.Engine.Util +{ + internal static class WorkerUtil + { + public static (Type RequestType, Type ResponseType) GetRequestResponseTypes(Type workerType) + { + var types = workerType.GetInterface(nameof(INgWorker))!.GetGenericArguments(); + return (types[0], types[1]); + } + } +} diff --git a/src/ConductorSharp.Patterns/Builders/CSharpLambdaTaskBuilder.cs b/src/ConductorSharp.Patterns/Builders/CSharpLambdaTaskBuilder.cs index bbe60fc8..c1fafdc4 100644 --- a/src/ConductorSharp.Patterns/Builders/CSharpLambdaTaskBuilder.cs +++ b/src/ConductorSharp.Patterns/Builders/CSharpLambdaTaskBuilder.cs @@ -10,7 +10,6 @@ using ConductorSharp.Patterns.Exceptions; using ConductorSharp.Patterns.Model; using ConductorSharp.Patterns.Tasks; -using MediatR; using Newtonsoft.Json.Linq; namespace ConductorSharp.Patterns.Builders @@ -24,7 +23,7 @@ public static ITaskOptionsBuilder AddTask( Func lambda ) where TWorkflow : ITypedWorkflow - where TInput : IRequest + where TInput : ITaskInput { var configurationProp = builder.ConfigurationProperties.FirstOrDefault(prop => prop.Key == CSharpLambdaTask.LambdaTaskNameConfigurationProperty) @@ -50,7 +49,7 @@ Func lambda } internal class CSharpLambdaTaskBuilder : BaseTaskBuilder - where TInput : IRequest + where TInput : ITaskInput { public const string LambdaIdStorageKey = "ConductorSharp.Engine.CSharpLambdaTaskBuilder.LambdaId"; diff --git a/src/ConductorSharp.Patterns/Model/CSharpLambdaTaskModel.cs b/src/ConductorSharp.Patterns/Model/CSharpLambdaTaskModel.cs index 1771348d..63ebde04 100644 --- a/src/ConductorSharp.Patterns/Model/CSharpLambdaTaskModel.cs +++ b/src/ConductorSharp.Patterns/Model/CSharpLambdaTaskModel.cs @@ -1,7 +1,8 @@ -using ConductorSharp.Engine.Model; -using MediatR; +using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Model; namespace ConductorSharp.Patterns.Model { - public class CSharpLambdaTaskModel : TaskModel where TInput : IRequest { } + public class CSharpLambdaTaskModel : TaskModel + where TInput : ITaskInput; } diff --git a/src/ConductorSharp.Patterns/Tasks/CSharpLambdaTask.cs b/src/ConductorSharp.Patterns/Tasks/CSharpLambdaTask.cs index 3cbc570c..32188a47 100644 --- a/src/ConductorSharp.Patterns/Tasks/CSharpLambdaTask.cs +++ b/src/ConductorSharp.Patterns/Tasks/CSharpLambdaTask.cs @@ -10,13 +10,12 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Util; using ConductorSharp.Patterns.Exceptions; -using MediatR; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace ConductorSharp.Patterns.Tasks { - internal class CSharpLambdaTaskInput : IRequest + internal class CSharpLambdaTaskInput : ITaskInput { public const string LambdaIdenfitierParamName = "lambda_identifier"; public const string TaskInputParamName = "task_input"; @@ -31,7 +30,7 @@ internal class CSharpLambdaTaskInput : IRequest } [OriginalName(TaskName)] - internal class CSharpLambdaTask(WorkflowBuildItemRegistry itemRegistry) : ITaskRequestHandler + internal class CSharpLambdaTask(WorkflowBuildItemRegistry itemRegistry) : INgWorker { public const string TaskName = "CSHRP_inln_lmbd"; public const string LambdaTaskNameConfigurationProperty = nameof(LambdaTaskNameConfigurationProperty); diff --git a/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs b/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs index 8e2fc3d4..26882710 100644 --- a/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs +++ b/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs @@ -6,6 +6,7 @@ using ConductorSharp.Client.Service; using ConductorSharp.Engine; using ConductorSharp.Engine.Builders.Metadata; +using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Util; using MediatR; using Newtonsoft.Json.Linq; @@ -13,7 +14,7 @@ namespace ConductorSharp.Patterns.Tasks { #region models - public class ReadWorkflowTasksRequest : IRequest + public class ReadWorkflowTasksRequest : ITaskInput { /// /// Comma separated list of task reference names to be read from specified workflow @@ -35,7 +36,7 @@ public record WorkflowDetails(JObject InputData); /// Uses the Conductor API to read the input/output and status of the specified tasks for the specified workflow. /// [OriginalName(Constants.TaskNamePrefix + "_read_tasks")] - public class ReadWorkflowTasks(IWorkflowService workflowService) : TaskRequestHandler + public class ReadWorkflowTasks(IWorkflowService workflowService) : NgWorker { private readonly IWorkflowService _workflowService = workflowService; diff --git a/src/ConductorSharp.Patterns/Tasks/WaitSeconds.cs b/src/ConductorSharp.Patterns/Tasks/WaitSeconds.cs index 9b683033..76f6a51a 100644 --- a/src/ConductorSharp.Patterns/Tasks/WaitSeconds.cs +++ b/src/ConductorSharp.Patterns/Tasks/WaitSeconds.cs @@ -1,16 +1,14 @@ -using System; -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; using System.Threading; using System.Threading.Tasks; using ConductorSharp.Engine; using ConductorSharp.Engine.Builders.Metadata; +using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; -using ConductorSharp.Engine.Util; -using MediatR; namespace ConductorSharp.Patterns.Tasks { - public class WaitSecondsRequest : IRequest + public class WaitSecondsRequest : ITaskInput { /// /// Time to wait in seconds @@ -24,7 +22,7 @@ public class WaitSecondsRequest : IRequest /// Executes `await Task.Delay(input.Seconds * 1000)` to wait for a given amount of seconds /// [OriginalName(Constants.TaskNamePrefix + "_wait_seconds")] - public class WaitSeconds : TaskRequestHandler + public class WaitSeconds : NgWorker { public override async Task Handle(WaitSecondsRequest input, CancellationToken cancellationToken) { diff --git a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs index bdf840fe..6b4213fd 100644 --- a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs +++ b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs @@ -20,7 +20,7 @@ public void NamingUtilShouldReturnCorrectNameableObjectName() Assert.Equal("CUSTOMER_get", NamingUtil.NameOf()); } - public class Request + public class Request : ITaskInput { public class Response { } @@ -46,8 +46,7 @@ CancellationToken cancellationToken } public class GenericMiddleware : INgWorkerMiddleware - where TResponse : class, new() - where TRequest : class, new() + where TRequest : class, ITaskInput, new() { public async Task Handle( TRequest request, diff --git a/test/ConductorSharp.Engine.Tests/Samples/Tasks/ArrayTask.cs b/test/ConductorSharp.Engine.Tests/Samples/Tasks/ArrayTask.cs index faecc69a..139e2435 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Tasks/ArrayTask.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Tasks/ArrayTask.cs @@ -1,12 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ConductorSharp.Engine.Tests.Samples.Tasks +namespace ConductorSharp.Engine.Tests.Samples.Tasks { - public class ArrayTaskInput : IRequest + public class ArrayTaskInput : ITaskInput { public class TestModel { @@ -19,7 +13,7 @@ public class TestModel public object Objects { get; set; } } - public class ArrayTaskOutput { } + public class ArrayTaskOutput; - public class ArrayTask : SimpleTaskModel { } + public class ArrayTask : SimpleTaskModel; } diff --git a/test/ConductorSharp.Engine.Tests/Samples/Tasks/CustomerGetV1.cs b/test/ConductorSharp.Engine.Tests/Samples/Tasks/CustomerGetV1.cs index e1290d9f..5b973682 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Tasks/CustomerGetV1.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Tasks/CustomerGetV1.cs @@ -2,7 +2,7 @@ namespace ConductorSharp.Engine.Tests.Samples.Tasks; -public partial class CustomerGetV1Input : IRequest +public partial class CustomerGetV1Input : ITaskInput { /// /// customer_id diff --git a/test/ConductorSharp.Engine.Tests/Samples/Tasks/DictionaryInputTask.cs b/test/ConductorSharp.Engine.Tests/Samples/Tasks/DictionaryInputTask.cs index 3bdec654..31abb28c 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Tasks/DictionaryInputTask.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Tasks/DictionaryInputTask.cs @@ -1,6 +1,6 @@ namespace ConductorSharp.Engine.Tests.Samples.Tasks; -public class DictionaryInputTaskInput : IRequest +public class DictionaryInputTaskInput : ITaskInput { public IDictionary Object { get; set; } public IDictionary StringObject { get; set; } diff --git a/test/ConductorSharp.Engine.Tests/Samples/Tasks/EmailPrepareV1.cs b/test/ConductorSharp.Engine.Tests/Samples/Tasks/EmailPrepareV1.cs index 387ed5eb..b3db6e72 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Tasks/EmailPrepareV1.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Tasks/EmailPrepareV1.cs @@ -2,7 +2,7 @@ namespace ConductorSharp.Engine.Tests.Samples.Tasks; -public partial class EmailPrepareV1Input : IRequest +public partial class EmailPrepareV1Input : ITaskInput { /// /// address diff --git a/test/ConductorSharp.Engine.Tests/Samples/Tasks/ListTask.cs b/test/ConductorSharp.Engine.Tests/Samples/Tasks/ListTask.cs index 123042fe..93c232ae 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Tasks/ListTask.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Tasks/ListTask.cs @@ -6,7 +6,7 @@ namespace ConductorSharp.Engine.Tests.Samples.Tasks { - public class ListTaskInput : IRequest + public class ListTaskInput : ITaskInput { public List List { get; set; } } diff --git a/test/ConductorSharp.Engine.Tests/Samples/Tasks/NestedObjects.cs b/test/ConductorSharp.Engine.Tests/Samples/Tasks/NestedObjects.cs index f6c7700c..1dafa031 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Tasks/NestedObjects.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Tasks/NestedObjects.cs @@ -1,13 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ConductorSharp.Engine.Builders.Metadata; +using ConductorSharp.Engine.Builders.Metadata; namespace ConductorSharp.Engine.Tests.Samples.Tasks { - public class TaskNestedObjectsInput : IRequest + public class TaskNestedObjectsInput : ITaskInput { public object NestedObjects { get; set; } } diff --git a/test/ConductorSharp.Engine.Tests/Samples/Tasks/TaskPropertiesTask.cs b/test/ConductorSharp.Engine.Tests/Samples/Tasks/TaskPropertiesTask.cs index b009bcdd..56443373 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Tasks/TaskPropertiesTask.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Tasks/TaskPropertiesTask.cs @@ -1,6 +1,6 @@ namespace ConductorSharp.Engine.Tests.Samples.Tasks { - public class TaskPropertiesTaskInput : IRequest + public class TaskPropertiesTaskInput : ITaskInput { public string Status { get; set; } public string TaskType { get; set; } @@ -13,7 +13,7 @@ public class TaskPropertiesTaskInput : IRequest public string CorrelationId { get; set; } } - public class TaskPropertiesTaskOutput { } + public class TaskPropertiesTaskOutput; - public class TaskPropertiesTask : SimpleTaskModel { } + public class TaskPropertiesTask : SimpleTaskModel; } diff --git a/test/ConductorSharp.Engine.Tests/Samples/Tasks/VersionSubworkflow.cs b/test/ConductorSharp.Engine.Tests/Samples/Tasks/VersionSubworkflow.cs index 5fcd557c..a8ba60b0 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Tasks/VersionSubworkflow.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Tasks/VersionSubworkflow.cs @@ -1,17 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ConductorSharp.Engine.Builders.Metadata; +using ConductorSharp.Engine.Builders.Metadata; namespace ConductorSharp.Engine.Tests.Samples.Tasks { - public class VersionSubworkflowInput : IRequest { } + public class VersionSubworkflowInput : ITaskInput { } - public class VersionSubworkflowOutput { } + public class VersionSubworkflowOutput; [OriginalName("TEST_subworkflow")] [Version(3)] - public class VersionSubworkflow : SubWorkflowTaskModel { } + public class VersionSubworkflow : SubWorkflowTaskModel; } diff --git a/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs b/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs index 4eb452c5..e25c1af8 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs @@ -3,7 +3,7 @@ namespace ConductorSharp.Engine.Tests.Samples.Workers; -public class GetCustomerRequest : IRequest +public class GetCustomerRequest : ITaskInput { [Required] [JsonProperty("id")] @@ -24,7 +24,7 @@ public class Customer } [OriginalName("CUSTOMER_get")] -public class GetCustomerHandler : TaskRequestHandler +public class GetCustomerHandler : NgWorker { public override Task Handle(GetCustomerRequest request, CancellationToken cancellationToken) => throw new NotImplementedException(); diff --git a/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs b/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs index 7039b55a..1c2ad582 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs @@ -2,7 +2,7 @@ namespace ConductorSharp.Engine.Tests.Samples.Workers; -public class PrepareEmailRequest : IRequest +public class PrepareEmailRequest : ITaskInput { public string CustomerName { get; set; } public string Address { get; set; } @@ -14,7 +14,7 @@ public class PrepareEmailResponse } [OriginalName("EMAIL_prepare")] -public class PrepareEmailHandler : TaskRequestHandler +public class PrepareEmailHandler : NgWorker { public override Task Handle(PrepareEmailRequest request, CancellationToken cancellationToken) => throw new NotImplementedException(); diff --git a/test/ConductorSharp.Engine.Tests/Samples/Workflows/CSharpLambdaWorkflow.cs b/test/ConductorSharp.Engine.Tests/Samples/Workflows/CSharpLambdaWorkflow.cs index c43ffe36..42f00558 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Workflows/CSharpLambdaWorkflow.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Workflows/CSharpLambdaWorkflow.cs @@ -15,7 +15,7 @@ public class CSharpLambdaWorkflowOutput : WorkflowOutput { } [WorkflowMetadata(OwnerEmail = "test@test.com")] public class CSharpLambdaWorkflow : Workflow { - public class LambdaTaskInput : IRequest + public class LambdaTaskInput : ITaskInput { public string LambdaInput { get; set; } } diff --git a/test/ConductorSharp.Engine.Tests/Samples/Workflows/DynamicTask.cs b/test/ConductorSharp.Engine.Tests/Samples/Workflows/DynamicTask.cs index 14a745fa..cbb4d646 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Workflows/DynamicTask.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Workflows/DynamicTask.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ConductorSharp.Engine.Builders.Metadata; +using ConductorSharp.Engine.Builders.Metadata; namespace ConductorSharp.Engine.Tests.Samples.Workflows { @@ -22,7 +17,7 @@ public class ExpectedDynamicOutput public string Name { get; set; } } - public class MandatoryDynamicInput : IRequest + public class MandatoryDynamicInput : ITaskInput { public int Count { get; set; } public bool ShouldUseNext { get; set; } diff --git a/test/ConductorSharp.Engine.Tests/Samples/Workflows/EventTaskWorkflow.cs b/test/ConductorSharp.Engine.Tests/Samples/Workflows/EventTaskWorkflow.cs index 1fcc00fa..d20a1657 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Workflows/EventTaskWorkflow.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Workflows/EventTaskWorkflow.cs @@ -9,7 +9,7 @@ public class EventTaskWorkflowOutput : WorkflowOutput { } [WorkflowMetadata(OwnerEmail = "test@test.com")] public class EventTaskWorkflow : Workflow { - public class EventTaskPayload : IRequest + public class EventTaskPayload : ITaskInput { public string PayloadParam { get; set; } } diff --git a/test/ConductorSharp.Engine.Tests/Samples/Workflows/StringAddition.cs b/test/ConductorSharp.Engine.Tests/Samples/Workflows/StringAddition.cs index c59243b7..e06f3a84 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Workflows/StringAddition.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Workflows/StringAddition.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ConductorSharp.Engine.Builders.Metadata; +using ConductorSharp.Engine.Builders.Metadata; namespace ConductorSharp.Engine.Tests.Samples.Workflows { @@ -22,7 +17,7 @@ public StringAddition(WorkflowDefinitionBuilder + public class StringTaskInput : ITaskInput { public string Input { get; set; } } From 9ba5c7debf26aa53e57959dca2ab032bb404aa4f Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Wed, 25 Jun 2025 01:57:15 +0200 Subject: [PATCH 05/35] Remove MediatR package --- .../Behaviors/CustomBehavior.cs | 13 +++++++++---- .../ConductorSharp.Definitions/Generated/Task.cs | 1 - .../Workflows/CSharpLambdaWorkflow.cs | 1 - .../Behaviors/PrepareEmailBehavior.cs | 1 - .../Behaviors/ErrorHandlingBehavior.cs | 1 - .../Behaviors/TaskExecutionTrackingBehavior.cs | 1 - .../Builders/EventTaskBuilder.cs | 1 - .../Builders/LambdaTaskBuilder.cs | 1 - .../ConductorSharp.Engine.csproj | 1 - src/ConductorSharp.Engine/Model/SimpleTaskModel.cs | 1 - .../Model/SubWorkflowTaskModel.cs | 1 - src/ConductorSharp.Engine/Model/TaskModel.cs | 1 - .../Model/TerminateTaskModel.cs | 1 - .../Extensions/ContainerBuilderExtensions.cs | 2 -- .../Tasks/ReadWorkflowTasks.cs | 1 - test/ConductorSharp.Engine.Tests/Usings.cs | 1 - 16 files changed, 9 insertions(+), 20 deletions(-) diff --git a/examples/ConductorSharp.Definitions/Behaviors/CustomBehavior.cs b/examples/ConductorSharp.Definitions/Behaviors/CustomBehavior.cs index fac029ec..8011de4c 100644 --- a/examples/ConductorSharp.Definitions/Behaviors/CustomBehavior.cs +++ b/examples/ConductorSharp.Definitions/Behaviors/CustomBehavior.cs @@ -1,9 +1,10 @@ -using MediatR; +using ConductorSharp.Engine.Interface; using Microsoft.Extensions.Logging; namespace ConductorSharp.Definitions.Behaviors { - internal class CustomBehavior : IPipelineBehavior + internal class CustomBehavior : INgWorkerMiddleware + where TRequest : class, ITaskInput, new() { private readonly ILogger> _logger; @@ -12,10 +13,14 @@ public CustomBehavior(ILogger> logger) _logger = logger; } - public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) + public async Task Handle( + TRequest request, + Func> next, + CancellationToken cancellationToken + ) { _logger.LogInformation("Executed before all behaviors"); - var response = await next(); + var response = await next(request, cancellationToken); _logger.LogInformation("Executed after all behaviors"); return response; } diff --git a/examples/ConductorSharp.Definitions/Generated/Task.cs b/examples/ConductorSharp.Definitions/Generated/Task.cs index d9dae6e5..52d4eed9 100644 --- a/examples/ConductorSharp.Definitions/Generated/Task.cs +++ b/examples/ConductorSharp.Definitions/Generated/Task.cs @@ -2,7 +2,6 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; using ConductorSharp.Engine.Util; -using MediatR; using Newtonsoft.Json; namespace ConductorSharp.Definitions.Generated diff --git a/examples/ConductorSharp.Definitions/Workflows/CSharpLambdaWorkflow.cs b/examples/ConductorSharp.Definitions/Workflows/CSharpLambdaWorkflow.cs index f7e8b605..84317cb6 100644 --- a/examples/ConductorSharp.Definitions/Workflows/CSharpLambdaWorkflow.cs +++ b/examples/ConductorSharp.Definitions/Workflows/CSharpLambdaWorkflow.cs @@ -4,7 +4,6 @@ using ConductorSharp.Engine.Model; using ConductorSharp.Patterns.Builders; using ConductorSharp.Patterns.Model; -using MediatR; namespace ConductorSharp.Definitions.Workflows { diff --git a/examples/ConductorSharp.NoApi/Behaviors/PrepareEmailBehavior.cs b/examples/ConductorSharp.NoApi/Behaviors/PrepareEmailBehavior.cs index 0ebc7922..1a88ec7e 100644 --- a/examples/ConductorSharp.NoApi/Behaviors/PrepareEmailBehavior.cs +++ b/examples/ConductorSharp.NoApi/Behaviors/PrepareEmailBehavior.cs @@ -1,6 +1,5 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.NoApi.Handlers; -using MediatR; using Microsoft.Extensions.Logging; namespace ConductorSharp.NoApi.Behaviors diff --git a/src/ConductorSharp.Engine/Behaviors/ErrorHandlingBehavior.cs b/src/ConductorSharp.Engine/Behaviors/ErrorHandlingBehavior.cs index 2036cbe0..fac913bf 100644 --- a/src/ConductorSharp.Engine/Behaviors/ErrorHandlingBehavior.cs +++ b/src/ConductorSharp.Engine/Behaviors/ErrorHandlingBehavior.cs @@ -3,7 +3,6 @@ using System.Threading.Tasks; using ConductorSharp.Engine.Exceptions; using ConductorSharp.Engine.Interface; -using MediatR; namespace ConductorSharp.Engine.Behaviors { diff --git a/src/ConductorSharp.Engine/Behaviors/TaskExecutionTrackingBehavior.cs b/src/ConductorSharp.Engine/Behaviors/TaskExecutionTrackingBehavior.cs index 9efc9863..12177fb9 100644 --- a/src/ConductorSharp.Engine/Behaviors/TaskExecutionTrackingBehavior.cs +++ b/src/ConductorSharp.Engine/Behaviors/TaskExecutionTrackingBehavior.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Util; -using MediatR; namespace ConductorSharp.Engine.Behaviors { diff --git a/src/ConductorSharp.Engine/Builders/EventTaskBuilder.cs b/src/ConductorSharp.Engine/Builders/EventTaskBuilder.cs index 83c8d092..67871157 100644 --- a/src/ConductorSharp.Engine/Builders/EventTaskBuilder.cs +++ b/src/ConductorSharp.Engine/Builders/EventTaskBuilder.cs @@ -5,7 +5,6 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; using ConductorSharp.Engine.Util.Builders; -using MediatR; namespace ConductorSharp.Engine.Builders { diff --git a/src/ConductorSharp.Engine/Builders/LambdaTaskBuilder.cs b/src/ConductorSharp.Engine/Builders/LambdaTaskBuilder.cs index 9533f860..0f3b9f8a 100644 --- a/src/ConductorSharp.Engine/Builders/LambdaTaskBuilder.cs +++ b/src/ConductorSharp.Engine/Builders/LambdaTaskBuilder.cs @@ -5,7 +5,6 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; using ConductorSharp.Engine.Util.Builders; -using MediatR; using Newtonsoft.Json.Linq; namespace ConductorSharp.Engine.Builders diff --git a/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj b/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj index 261e77bb..9995d4ae 100644 --- a/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj +++ b/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj @@ -16,7 +16,6 @@ - diff --git a/src/ConductorSharp.Engine/Model/SimpleTaskModel.cs b/src/ConductorSharp.Engine/Model/SimpleTaskModel.cs index f399103a..27f8d410 100644 --- a/src/ConductorSharp.Engine/Model/SimpleTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/SimpleTaskModel.cs @@ -1,5 +1,4 @@ using ConductorSharp.Engine.Interface; -using MediatR; namespace ConductorSharp.Engine.Model { diff --git a/src/ConductorSharp.Engine/Model/SubWorkflowTaskModel.cs b/src/ConductorSharp.Engine/Model/SubWorkflowTaskModel.cs index 5b0db52f..2eaa0c6a 100644 --- a/src/ConductorSharp.Engine/Model/SubWorkflowTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/SubWorkflowTaskModel.cs @@ -1,5 +1,4 @@ using ConductorSharp.Engine.Interface; -using MediatR; namespace ConductorSharp.Engine.Model { diff --git a/src/ConductorSharp.Engine/Model/TaskModel.cs b/src/ConductorSharp.Engine/Model/TaskModel.cs index ff919ecd..e15b5301 100644 --- a/src/ConductorSharp.Engine/Model/TaskModel.cs +++ b/src/ConductorSharp.Engine/Model/TaskModel.cs @@ -1,5 +1,4 @@ using ConductorSharp.Engine.Interface; -using MediatR; using Newtonsoft.Json; namespace ConductorSharp.Engine.Model diff --git a/src/ConductorSharp.Engine/Model/TerminateTaskModel.cs b/src/ConductorSharp.Engine/Model/TerminateTaskModel.cs index 2deb0c6e..0b31e3fa 100644 --- a/src/ConductorSharp.Engine/Model/TerminateTaskModel.cs +++ b/src/ConductorSharp.Engine/Model/TerminateTaskModel.cs @@ -1,6 +1,5 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Util; -using MediatR; using Newtonsoft.Json; namespace ConductorSharp.Engine.Model diff --git a/src/ConductorSharp.Patterns/Extensions/ContainerBuilderExtensions.cs b/src/ConductorSharp.Patterns/Extensions/ContainerBuilderExtensions.cs index 8aecc193..8576cba1 100644 --- a/src/ConductorSharp.Patterns/Extensions/ContainerBuilderExtensions.cs +++ b/src/ConductorSharp.Patterns/Extensions/ContainerBuilderExtensions.cs @@ -13,7 +13,6 @@ public static IExecutionManagerBuilder AddConductorSharpPatterns(this IExecution { executionManagerBuilder.Builder.RegisterWorkerTask(); executionManagerBuilder.Builder.RegisterWorkerTask(); - executionManagerBuilder.Builder.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(typeof(WaitSeconds).Assembly)); return executionManagerBuilder; } @@ -27,7 +26,6 @@ public static IExecutionManagerBuilder AddCSharpLambdaTasks( { options.OwnerEmail = "owneremail@gmail.com"; }); - executionManagerBuilder.Builder.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(typeof(CSharpLambdaTask).Assembly)); executionManagerBuilder.Builder.AddSingleton( new ConfigurationProperty(CSharpLambdaTask.LambdaTaskNameConfigurationProperty, csharpLambdaTaskNamePrefix) ); diff --git a/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs b/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs index 26882710..9cbe3569 100644 --- a/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs +++ b/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs @@ -8,7 +8,6 @@ using ConductorSharp.Engine.Builders.Metadata; using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Util; -using MediatR; using Newtonsoft.Json.Linq; namespace ConductorSharp.Patterns.Tasks diff --git a/test/ConductorSharp.Engine.Tests/Usings.cs b/test/ConductorSharp.Engine.Tests/Usings.cs index eb6fe6a9..f02300d2 100644 --- a/test/ConductorSharp.Engine.Tests/Usings.cs +++ b/test/ConductorSharp.Engine.Tests/Usings.cs @@ -3,6 +3,5 @@ global using ConductorSharp.Engine.Model; global using ConductorSharp.Engine.Tests.Samples.Tasks; global using ConductorSharp.Engine.Util; -global using MediatR; global using Newtonsoft.Json; global using Xunit; From 98fcf8c868b990851222d9a342dc809c302e3310 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Wed, 25 Jun 2025 10:26:22 +0200 Subject: [PATCH 06/35] Fix issue with retrieving type interfaces --- src/ConductorSharp.Engine/Util/WorkerUtil.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ConductorSharp.Engine/Util/WorkerUtil.cs b/src/ConductorSharp.Engine/Util/WorkerUtil.cs index 68dc755d..71f85009 100644 --- a/src/ConductorSharp.Engine/Util/WorkerUtil.cs +++ b/src/ConductorSharp.Engine/Util/WorkerUtil.cs @@ -7,7 +7,7 @@ internal static class WorkerUtil { public static (Type RequestType, Type ResponseType) GetRequestResponseTypes(Type workerType) { - var types = workerType.GetInterface(nameof(INgWorker))!.GetGenericArguments(); + var types = workerType.GetInterface(typeof(INgWorker<,>).Name)!.GetGenericArguments(); return (types[0], types[1]); } } From 8da6d4ae14952a4d3cc96c560f621f9688eecf68 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Wed, 25 Jun 2025 11:29:35 +0200 Subject: [PATCH 07/35] Remove assemblies parameter --- .../Extensions/ServiceCollectionExtensions.cs | 3 +- .../ConductorSharp.Definitions/Program.cs | 3 +- examples/ConductorSharp.NoApi/Program.cs | 3 +- .../Extensions/ConductorSharpBuilder.cs | 8 +---- .../Extensions/IConductorSharpBuilder.cs | 8 +---- .../Integration/WorkflowBuilderTests.cs | 2 +- .../Unit/ContainerBuilderTests.cs | 32 +++---------------- .../Unit/TaskDefinitionBuilderTests.cs | 2 +- .../Unit/WorkflowItemRegistryTests.cs | 16 ++-------- 9 files changed, 13 insertions(+), 64 deletions(-) diff --git a/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs b/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs index ce5f0827..9bb7414b 100644 --- a/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs +++ b/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs @@ -16,8 +16,7 @@ public static IServiceCollection ConfigureApiEnabled(this IServiceCollection hos maxConcurrentWorkers: configuration.GetValue("Conductor:MaxConcurrentWorkers"), sleepInterval: configuration.GetValue("Conductor:SleepInterval"), longPollInterval: configuration.GetValue("Conductor:LongPollInterval"), - domain: configuration.GetValue("Conductor:WorkerDomain"), - typeof(ServiceCollectionExtensions).Assembly + domain: configuration.GetValue("Conductor:WorkerDomain") ) .SetHealthCheckService() .AddPipelines(pipelines => diff --git a/examples/ConductorSharp.Definitions/Program.cs b/examples/ConductorSharp.Definitions/Program.cs index dc14223f..9e89262d 100644 --- a/examples/ConductorSharp.Definitions/Program.cs +++ b/examples/ConductorSharp.Definitions/Program.cs @@ -25,8 +25,7 @@ maxConcurrentWorkers: configuration.GetValue("Conductor:MaxConcurrentWorkers"), sleepInterval: configuration.GetValue("Conductor:SleepInterval"), longPollInterval: configuration.GetValue("Conductor:LongPollInterval"), - domain: configuration.GetValue("Conductor:WorkerDomain"), - typeof(Program).Assembly + domain: configuration.GetValue("Conductor:WorkerDomain") ) .AddConductorSharpPatterns() .SetHealthCheckService() diff --git a/examples/ConductorSharp.NoApi/Program.cs b/examples/ConductorSharp.NoApi/Program.cs index 48529228..548fd64c 100644 --- a/examples/ConductorSharp.NoApi/Program.cs +++ b/examples/ConductorSharp.NoApi/Program.cs @@ -28,8 +28,7 @@ maxConcurrentWorkers: configuration.GetValue("Conductor:MaxConcurrentWorkers"), sleepInterval: configuration.GetValue("Conductor:SleepInterval"), longPollInterval: configuration.GetValue("Conductor:LongPollInterval"), - domain: configuration.GetValue("Conductor:WorkerDomain"), - handlerAssemblies: typeof(Program).Assembly + domain: configuration.GetValue("Conductor:WorkerDomain") ) .SetHealthCheckService() .AddPipelines(pipelines => diff --git a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs index 513f7f98..e3ea7d78 100644 --- a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs @@ -17,13 +17,7 @@ public class ConductorSharpBuilder(IServiceCollection builder) : IConductorSharp { public IServiceCollection Builder { get; set; } = builder; - public IExecutionManagerBuilder AddExecutionManager( - int maxConcurrentWorkers, - int sleepInterval, - int longPollInterval, - string domain = null, - params Assembly[] handlerAssemblies - ) + public IExecutionManagerBuilder AddExecutionManager(int maxConcurrentWorkers, int sleepInterval, int longPollInterval, string domain = null) { var workerConfig = new WorkerSetConfig { diff --git a/src/ConductorSharp.Engine/Extensions/IConductorSharpBuilder.cs b/src/ConductorSharp.Engine/Extensions/IConductorSharpBuilder.cs index c381b887..c114b4c9 100644 --- a/src/ConductorSharp.Engine/Extensions/IConductorSharpBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/IConductorSharpBuilder.cs @@ -8,13 +8,7 @@ namespace ConductorSharp.Engine.Extensions { public interface IConductorSharpBuilder { - IExecutionManagerBuilder AddExecutionManager( - int maxConcurrentWorkers, - int sleepInterval, - int longPollInterval, - string domain = null, - params Assembly[] handlerAssemblies - ); + IExecutionManagerBuilder AddExecutionManager(int maxConcurrentWorkers, int sleepInterval, int longPollInterval, string domain = null); IConductorSharpBuilder SetBuildConfiguration(BuildConfiguration buildConfiguration); IConductorSharpBuilder AddAlternateClient(string baseUrl, string key, string apiPath = "api", bool ignoreInvalidCertificate = false); } diff --git a/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs b/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs index 7c1dcc9d..8ef5b365 100644 --- a/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs +++ b/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs @@ -313,7 +313,7 @@ private static IServiceProvider RegisterWorkflow() containerBuilder .AddConductorSharp("example.com/api") .SetBuildConfiguration(new() { DefaultOwnerEmail = null }) - .AddExecutionManager(10, 100, 100, null, typeof(WorkflowBuilderTests).Assembly) + .AddExecutionManager(10, 100, 100, null) .AddPipelines(pipelines => { pipelines.AddContextLogging(); diff --git a/test/ConductorSharp.Engine.Tests/Unit/ContainerBuilderTests.cs b/test/ConductorSharp.Engine.Tests/Unit/ContainerBuilderTests.cs index 75669f41..9145a270 100644 --- a/test/ConductorSharp.Engine.Tests/Unit/ContainerBuilderTests.cs +++ b/test/ConductorSharp.Engine.Tests/Unit/ContainerBuilderTests.cs @@ -18,13 +18,7 @@ public void AppliesBuildConfigurationDefaults() builder .AddConductorSharp(baseUrl: "http://empty/empty") .SetBuildConfiguration(new BuildConfiguration { DefaultOwnerApp = "testApp", DefaultOwnerEmail = "owner@test.app" }) - .AddExecutionManager( - maxConcurrentWorkers: 1, - sleepInterval: 1, - longPollInterval: 1, - domain: null, - handlerAssemblies: typeof(ContainerBuilderTests).Assembly - ); + .AddExecutionManager(maxConcurrentWorkers: 1, sleepInterval: 1, longPollInterval: 1, domain: null); builder.RegisterWorkflow(); var container = builder.BuildServiceProvider(); @@ -42,13 +36,7 @@ public void OverridesBuildConfigurationDefaults() builder .AddConductorSharp(baseUrl: "http://empty/empty") .SetBuildConfiguration(new BuildConfiguration { DefaultOwnerApp = "testApp", DefaultOwnerEmail = "owner@test.app", }) - .AddExecutionManager( - maxConcurrentWorkers: 1, - sleepInterval: 1, - longPollInterval: 1, - null, - handlerAssemblies: typeof(ContainerBuilderTests).Assembly - ); + .AddExecutionManager(maxConcurrentWorkers: 1, sleepInterval: 1, longPollInterval: 1, null); builder.RegisterWorkflow(new BuildConfiguration { DefaultOwnerApp = overrideValue }); var container = builder.BuildServiceProvider(); @@ -64,13 +52,7 @@ public void ResolveWorkflowDependencies() var builder = new ServiceCollection(); builder .AddConductorSharp(baseUrl: "http://empty/empty") - .AddExecutionManager( - maxConcurrentWorkers: 1, - sleepInterval: 1, - longPollInterval: 1, - null, - handlerAssemblies: typeof(ContainerBuilderTests).Assembly - ); + .AddExecutionManager(maxConcurrentWorkers: 1, sleepInterval: 1, longPollInterval: 1, null); builder.AddTransient(); builder.RegisterWorkflow(); @@ -85,13 +67,7 @@ public void FailsToResolveWorkflowDependencies() var builder = new ServiceCollection(); builder .AddConductorSharp(baseUrl: "http://empty/empty") - .AddExecutionManager( - maxConcurrentWorkers: 1, - sleepInterval: 1, - longPollInterval: 1, - null, - handlerAssemblies: typeof(ContainerBuilderTests).Assembly - ); + .AddExecutionManager(maxConcurrentWorkers: 1, sleepInterval: 1, longPollInterval: 1, null); builder.RegisterWorkflow(); var container = builder.BuildServiceProvider(); diff --git a/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs b/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs index c0d5730a..fc83eebe 100644 --- a/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs +++ b/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs @@ -17,7 +17,7 @@ public TaskDefinitionBuilderTests() _containerBuilder .AddConductorSharp("http://example.com/api") - .AddExecutionManager(10, 100, 100, null, typeof(TaskDefinitionBuilderTests).Assembly) + .AddExecutionManager(10, 100, 100, null) .AddPipelines(pipelines => { pipelines.AddContextLogging(); diff --git a/test/ConductorSharp.Engine.Tests/Unit/WorkflowItemRegistryTests.cs b/test/ConductorSharp.Engine.Tests/Unit/WorkflowItemRegistryTests.cs index 26dfaf2d..0fa39be1 100644 --- a/test/ConductorSharp.Engine.Tests/Unit/WorkflowItemRegistryTests.cs +++ b/test/ConductorSharp.Engine.Tests/Unit/WorkflowItemRegistryTests.cs @@ -14,13 +14,7 @@ public void RegisteredItemsResolve() builder .AddConductorSharp(baseUrl: "http://empty/empty") - .AddExecutionManager( - maxConcurrentWorkers: 1, - sleepInterval: 1, - longPollInterval: 1, - null, - handlerAssemblies: typeof(WorkflowItemRegistryTests).Assembly - ); + .AddExecutionManager(maxConcurrentWorkers: 1, sleepInterval: 1, longPollInterval: 1, null); builder.RegisterWorkflow(); var container = builder.BuildServiceProvider(); @@ -42,13 +36,7 @@ public void GetAllCorrectlyResolves() builder .AddConductorSharp(baseUrl: "http://empty/empty") - .AddExecutionManager( - maxConcurrentWorkers: 1, - sleepInterval: 1, - longPollInterval: 1, - null, - handlerAssemblies: typeof(WorkflowItemRegistryTests).Assembly - ); + .AddExecutionManager(maxConcurrentWorkers: 1, sleepInterval: 1, longPollInterval: 1, null); builder.RegisterWorkflow(); var container = builder.BuildServiceProvider(); From f3ee402a95e75a71bac46a7890b23324ed7f59d6 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sat, 28 Jun 2025 02:17:55 +0200 Subject: [PATCH 08/35] Remove references to MediatR behaviors --- .../Behaviors/CustomBehavior.cs | 28 ------- .../Middlewares/CustomMiddleware.cs | 27 +++++++ .../ConductorSharp.Definitions/Program.cs | 4 +- .../Behaviors/PrepareEmailBehavior.cs | 28 ------- .../MIddlewares/PrepareEmailMiddleware.cs | 27 +++++++ examples/ConductorSharp.NoApi/Program.cs | 4 +- .../Behaviors/ContextLoggingBehavior.cs | 31 ------- .../Behaviors/ErrorHandlingBehavior.cs | 29 ------- .../RequestResponseLoggingBehavior.cs | 81 ------------------- .../TaskExecutionTrackingBehavior.cs | 66 --------------- .../Behaviors/ValidationBehavior.cs | 23 ------ .../Exceptions/BaseWorkerException.cs | 9 --- .../Extensions/ConductorSharpBuilder.cs | 4 +- .../Extensions/IPipelineBuilder.cs | 4 +- .../Extensions/PipelineBuilder.cs | 16 ++-- .../Middlewares/ContextLoggingMiddleware.cs | 30 +++++++ .../RequestResponseLoggingBehavior.cs | 80 ++++++++++++++++++ .../TaskExecutionTrackingMiddleware.cs | 61 ++++++++++++++ .../Middlewares/ValidationWorkerMiddleware.cs | 22 +++++ 19 files changed, 262 insertions(+), 312 deletions(-) delete mode 100644 examples/ConductorSharp.Definitions/Behaviors/CustomBehavior.cs create mode 100644 examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs delete mode 100644 examples/ConductorSharp.NoApi/Behaviors/PrepareEmailBehavior.cs create mode 100644 examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs delete mode 100644 src/ConductorSharp.Engine/Behaviors/ContextLoggingBehavior.cs delete mode 100644 src/ConductorSharp.Engine/Behaviors/ErrorHandlingBehavior.cs delete mode 100644 src/ConductorSharp.Engine/Behaviors/RequestResponseLoggingBehavior.cs delete mode 100644 src/ConductorSharp.Engine/Behaviors/TaskExecutionTrackingBehavior.cs delete mode 100644 src/ConductorSharp.Engine/Behaviors/ValidationBehavior.cs delete mode 100644 src/ConductorSharp.Engine/Exceptions/BaseWorkerException.cs create mode 100644 src/ConductorSharp.Engine/Middlewares/ContextLoggingMiddleware.cs create mode 100644 src/ConductorSharp.Engine/Middlewares/RequestResponseLoggingBehavior.cs create mode 100644 src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs create mode 100644 src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs diff --git a/examples/ConductorSharp.Definitions/Behaviors/CustomBehavior.cs b/examples/ConductorSharp.Definitions/Behaviors/CustomBehavior.cs deleted file mode 100644 index 8011de4c..00000000 --- a/examples/ConductorSharp.Definitions/Behaviors/CustomBehavior.cs +++ /dev/null @@ -1,28 +0,0 @@ -using ConductorSharp.Engine.Interface; -using Microsoft.Extensions.Logging; - -namespace ConductorSharp.Definitions.Behaviors -{ - internal class CustomBehavior : INgWorkerMiddleware - where TRequest : class, ITaskInput, new() - { - private readonly ILogger> _logger; - - public CustomBehavior(ILogger> logger) - { - _logger = logger; - } - - public async Task Handle( - TRequest request, - Func> next, - CancellationToken cancellationToken - ) - { - _logger.LogInformation("Executed before all behaviors"); - var response = await next(request, cancellationToken); - _logger.LogInformation("Executed after all behaviors"); - return response; - } - } -} diff --git a/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs b/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs new file mode 100644 index 00000000..f554555f --- /dev/null +++ b/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs @@ -0,0 +1,27 @@ +using ConductorSharp.Engine.Interface; +using Microsoft.Extensions.Logging; + +namespace ConductorSharp.Definitions.Middlewares; + +internal class CustomMiddleware : INgWorkerMiddleware + where TRequest : class, ITaskInput, new() +{ + private readonly ILogger> _logger; + + public CustomMiddleware(ILogger> logger) + { + _logger = logger; + } + + public async Task Handle( + TRequest request, + Func> next, + CancellationToken cancellationToken + ) + { + _logger.LogInformation("Executed before all middlewares"); + var response = await next(request, cancellationToken); + _logger.LogInformation("Executed after all middlewares"); + return response; + } +} diff --git a/examples/ConductorSharp.Definitions/Program.cs b/examples/ConductorSharp.Definitions/Program.cs index 9e89262d..9c2321d7 100644 --- a/examples/ConductorSharp.Definitions/Program.cs +++ b/examples/ConductorSharp.Definitions/Program.cs @@ -1,4 +1,4 @@ -using ConductorSharp.Definitions.Behaviors; +using ConductorSharp.Definitions.Middlewares; using ConductorSharp.Definitions.Workflows; using ConductorSharp.Engine.Extensions; using ConductorSharp.Engine.Health; @@ -31,7 +31,7 @@ .SetHealthCheckService() .AddPipelines(pipelines => { - pipelines.AddCustomBehavior(typeof(CustomBehavior<,>)); + pipelines.AddCustomMiddleware(typeof(CustomMiddleware<,>)); pipelines.AddRequestResponseLogging(); pipelines.AddValidation(); }) diff --git a/examples/ConductorSharp.NoApi/Behaviors/PrepareEmailBehavior.cs b/examples/ConductorSharp.NoApi/Behaviors/PrepareEmailBehavior.cs deleted file mode 100644 index 1a88ec7e..00000000 --- a/examples/ConductorSharp.NoApi/Behaviors/PrepareEmailBehavior.cs +++ /dev/null @@ -1,28 +0,0 @@ -using ConductorSharp.Engine.Interface; -using ConductorSharp.NoApi.Handlers; -using Microsoft.Extensions.Logging; - -namespace ConductorSharp.NoApi.Behaviors -{ - internal class PrepareEmailBehavior : INgWorkerMiddleware - { - private readonly ILogger _logger; - - public PrepareEmailBehavior(ILogger logger) - { - _logger = logger; - } - - public async Task Handle( - PrepareEmailRequest request, - Func> next, - CancellationToken cancellationToken - ) - { - _logger.LogInformation($"Executed only before {nameof(PrepareEmailHandler)}"); - var response = await next(request, cancellationToken); - _logger.LogInformation($"Executed only after {nameof(PrepareEmailHandler)}"); - return response; - } - } -} diff --git a/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs b/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs new file mode 100644 index 00000000..2f436044 --- /dev/null +++ b/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs @@ -0,0 +1,27 @@ +using ConductorSharp.Engine.Interface; +using ConductorSharp.NoApi.Handlers; +using Microsoft.Extensions.Logging; + +namespace ConductorSharp.NoApi.MIddlewares; + +internal class PrepareEmailMiddleware : INgWorkerMiddleware +{ + private readonly ILogger _logger; + + public PrepareEmailMiddleware(ILogger logger) + { + _logger = logger; + } + + public async Task Handle( + PrepareEmailRequest request, + Func> next, + CancellationToken cancellationToken + ) + { + _logger.LogInformation($"Executed only before {nameof(PrepareEmailHandler)}"); + var response = await next(request, cancellationToken); + _logger.LogInformation($"Executed only after {nameof(PrepareEmailHandler)}"); + return response; + } +} diff --git a/examples/ConductorSharp.NoApi/Program.cs b/examples/ConductorSharp.NoApi/Program.cs index 548fd64c..a92f8ec7 100644 --- a/examples/ConductorSharp.NoApi/Program.cs +++ b/examples/ConductorSharp.NoApi/Program.cs @@ -1,8 +1,8 @@ using ConductorSharp.Engine.Extensions; using ConductorSharp.Engine.Health; using ConductorSharp.KafkaCancellationNotifier.Extensions; -using ConductorSharp.NoApi.Behaviors; using ConductorSharp.NoApi.Handlers; +using ConductorSharp.NoApi.MIddlewares; using ConductorSharp.Patterns.Extensions; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -36,7 +36,7 @@ pipelines.AddContextLogging(); pipelines.AddRequestResponseLogging(); pipelines.AddValidation(); - pipelines.AddCustomBehavior(); + pipelines.AddCustomMiddleware(); }) .AddConductorSharpPatterns(); //.AddKafkaCancellationNotifier( diff --git a/src/ConductorSharp.Engine/Behaviors/ContextLoggingBehavior.cs b/src/ConductorSharp.Engine/Behaviors/ContextLoggingBehavior.cs deleted file mode 100644 index 4872ac3d..00000000 --- a/src/ConductorSharp.Engine/Behaviors/ContextLoggingBehavior.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using ConductorSharp.Engine.Interface; -using ConductorSharp.Engine.Util; -using Serilog.Context; - -namespace ConductorSharp.Engine.Behaviors -{ - public class ContextLoggingBehavior : INgWorkerMiddleware - where TRequest : class, ITaskInput, new() - { - private readonly ConductorSharpExecutionContext _executionContext; - private const string LoggerPropertyName = "ConductorContext"; - - public ContextLoggingBehavior(ConductorSharpExecutionContext executionContext) - { - _executionContext = executionContext; - } - - public async Task Handle( - TRequest request, - Func> next, - CancellationToken cancellationToken - ) - { - using var _ = LogContext.PushProperty(LoggerPropertyName, _executionContext, true); - return await next(request, cancellationToken); - } - } -} diff --git a/src/ConductorSharp.Engine/Behaviors/ErrorHandlingBehavior.cs b/src/ConductorSharp.Engine/Behaviors/ErrorHandlingBehavior.cs deleted file mode 100644 index fac913bf..00000000 --- a/src/ConductorSharp.Engine/Behaviors/ErrorHandlingBehavior.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using ConductorSharp.Engine.Exceptions; -using ConductorSharp.Engine.Interface; - -namespace ConductorSharp.Engine.Behaviors -{ - // TODO: Consider removing - public class ErrorHandlingBehavior : INgWorkerMiddleware - where TRequest : class, ITaskInput, new() - { - public async Task Handle( - TRequest request, - Func> next, - CancellationToken cancellationToken - ) - { - try - { - return await next(request, cancellationToken); - } - catch (Exception ex) - { - throw new BaseWorkerException(ex.Message, ex); - } - } - } -} diff --git a/src/ConductorSharp.Engine/Behaviors/RequestResponseLoggingBehavior.cs b/src/ConductorSharp.Engine/Behaviors/RequestResponseLoggingBehavior.cs deleted file mode 100644 index f7d7ce27..00000000 --- a/src/ConductorSharp.Engine/Behaviors/RequestResponseLoggingBehavior.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using ConductorSharp.Engine.Interface; -using ConductorSharp.Engine.Util; -using Microsoft.Extensions.Logging; - -namespace ConductorSharp.Engine.Behaviors -{ - // TODO: Consider removing this - public class RequestResponseLoggingBehavior : INgWorkerMiddleware - where TRequest : class, ITaskInput, new() - { - private readonly ILogger> _logger; - private readonly ConductorSharpExecutionContext _context; - - public RequestResponseLoggingBehavior( - ILogger> logger, - ConductorSharpExecutionContext context - ) - { - _logger = logger; - _context = context; - } - - public async Task Handle( - TRequest request, - Func> next, - CancellationToken cancellationToken - ) - { - var requestId = Guid.NewGuid(); - var requestName = typeof(TRequest).Name; - - var stopwatch = new Stopwatch(); - - _logger.LogInformation( - $"Submitting request {{Request}} with payload {{@{requestName}}} and with id {{RequestId}}", - requestName, - request, - requestId - ); - stopwatch.Start(); - - try - { - var response = await next(request, cancellationToken); - - stopwatch.Stop(); - - _logger.LogInformation( - $"Received response {{@Response}} for request {{Request}} with id {{RequestId}} (exec time = {{ElapsedMilliseconds}})", - response, - requestName, - requestId, - stopwatch.ElapsedMilliseconds - ); - - return response; - } - catch (OperationCanceledException) when (_context.TaskId != null) - { - // Simply rethrow and do not log in order for cancellation notifier to work - throw; - } - catch (Exception exc) - { - stopwatch.Stop(); - _logger.LogError( - $"Exception occured {{@Exception}} for request {{Request}} with id {{RequestId}} (exec time = {{ElapsedMilliseconds}})", - exc, - requestName, - requestId, - stopwatch.ElapsedMilliseconds - ); - throw; - } - } - } -} diff --git a/src/ConductorSharp.Engine/Behaviors/TaskExecutionTrackingBehavior.cs b/src/ConductorSharp.Engine/Behaviors/TaskExecutionTrackingBehavior.cs deleted file mode 100644 index 12177fb9..00000000 --- a/src/ConductorSharp.Engine/Behaviors/TaskExecutionTrackingBehavior.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using ConductorSharp.Engine.Interface; -using ConductorSharp.Engine.Util; - -namespace ConductorSharp.Engine.Behaviors -{ - public class TaskExecutionTrackingBehavior : INgWorkerMiddleware - where TRequest : class, ITaskInput, new() - { - private readonly ConductorSharpExecutionContext _executionContext; - private readonly IEnumerable _taskExecutionServices; - - public TaskExecutionTrackingBehavior( - ConductorSharpExecutionContext executionContext, - IEnumerable taskExecutionServices - ) - { - _executionContext = executionContext; - _taskExecutionServices = taskExecutionServices; - } - - public async Task Handle( - TRequest request, - Func> next, - CancellationToken cancellationToken - ) - { - var trackedTask = new RunningTask - { - TaskId = _executionContext.TaskId, - TaskName = _executionContext.TaskName, - StartedAt = DateTimeOffset.UtcNow - }; - - foreach (var taskExecutionService in _taskExecutionServices) - { - await taskExecutionService.OnPolled(trackedTask); - } - - try - { - var response = await next(request, cancellationToken); - - foreach (var taskExecutionService in _taskExecutionServices) - { - await taskExecutionService.OnCompleted(trackedTask); - } - - return response; - } - catch (Exception) - { - foreach (var taskExecutionService in _taskExecutionServices) - { - await taskExecutionService.OnFailed(trackedTask); - } - - throw; - } - } - } -} diff --git a/src/ConductorSharp.Engine/Behaviors/ValidationBehavior.cs b/src/ConductorSharp.Engine/Behaviors/ValidationBehavior.cs deleted file mode 100644 index d02a3313..00000000 --- a/src/ConductorSharp.Engine/Behaviors/ValidationBehavior.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using ConductorSharp.Engine.Interface; -using ConductorSharp.Engine.Util; - -namespace ConductorSharp.Engine.Behaviors -{ - public class ValidationWorkerMiddleware : INgWorkerMiddleware - where TRequest : class, ITaskInput, new() - { - public async Task Handle( - TRequest request, - Func> next, - CancellationToken cancellationToken - ) - { - ObjectValidator.Validate(request); - var response = await next(request, cancellationToken); - return response; - } - } -} diff --git a/src/ConductorSharp.Engine/Exceptions/BaseWorkerException.cs b/src/ConductorSharp.Engine/Exceptions/BaseWorkerException.cs deleted file mode 100644 index 680753c2..00000000 --- a/src/ConductorSharp.Engine/Exceptions/BaseWorkerException.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace ConductorSharp.Engine.Exceptions -{ - public class BaseWorkerException : Exception - { - public BaseWorkerException(string message, Exception innerException) : base(message, innerException) { } - } -} diff --git a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs index e3ea7d78..e009cbbc 100644 --- a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs @@ -58,10 +58,10 @@ public IExecutionManagerBuilder UseBetaExecutionManager() return this; } - public IExecutionManagerBuilder AddPipelines(Action behaviorBuilder) + public IExecutionManagerBuilder AddPipelines(Action middlewareBuilder) { var pipelineBuilder = new PipelineBuilder(Builder); - behaviorBuilder(pipelineBuilder); + middlewareBuilder(pipelineBuilder); return this; } diff --git a/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs index 8cdda617..27e39b25 100644 --- a/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs @@ -9,9 +9,9 @@ public interface IPipelineBuilder void AddValidation(); void AddContextLogging(); void AddExecutionTaskTracking(); - void AddCustomBehavior(Type behaviorType); + void AddCustomMiddleware(Type middlewareType); - void AddCustomBehavior() + void AddCustomMiddleware() where TWorkerMiddleware : class, INgWorkerMiddleware where TRequest : class, ITaskInput, new(); } diff --git a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs index 59a730b8..cb9adcbc 100644 --- a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs @@ -1,6 +1,6 @@ using System; -using ConductorSharp.Engine.Behaviors; using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Middlewares; using Microsoft.Extensions.DependencyInjection; namespace ConductorSharp.Engine.Extensions; @@ -8,21 +8,19 @@ namespace ConductorSharp.Engine.Extensions; internal class PipelineBuilder(IServiceCollection serviceCollection) : IPipelineBuilder { public void AddRequestResponseLogging() => - serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(RequestResponseLoggingBehavior<,>)); + serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(RequestResponseLoggingMiddleware<,>)); public void AddValidation() => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(ValidationWorkerMiddleware<,>)); - public void AddContextLogging() => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(ContextLoggingBehavior<,>)); + public void AddContextLogging() => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(ContextLoggingMiddleware<,>)); public void AddExecutionTaskTracking() => - serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(TaskExecutionTrackingBehavior<,>)); + serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(TaskExecutionTrackingMiddleware<,>)); - public void AddCustomBehavior(Type behaviorType) => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), behaviorType); + public void AddCustomMiddleware(Type middlewareType) => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), middlewareType); - public void AddCustomBehavior() + public void AddCustomMiddleware() where TWorkerMiddleware : class, INgWorkerMiddleware - where TRequest : class, ITaskInput, new() - { + where TRequest : class, ITaskInput, new() => serviceCollection.AddTransient, TWorkerMiddleware>(); - } } diff --git a/src/ConductorSharp.Engine/Middlewares/ContextLoggingMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/ContextLoggingMiddleware.cs new file mode 100644 index 00000000..a2bbf9dd --- /dev/null +++ b/src/ConductorSharp.Engine/Middlewares/ContextLoggingMiddleware.cs @@ -0,0 +1,30 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; +using Serilog.Context; + +namespace ConductorSharp.Engine.Middlewares; + +public class ContextLoggingMiddleware : INgWorkerMiddleware + where TRequest : class, ITaskInput, new() +{ + private readonly ConductorSharpExecutionContext _executionContext; + private const string LoggerPropertyName = "ConductorContext"; + + public ContextLoggingMiddleware(ConductorSharpExecutionContext executionContext) + { + _executionContext = executionContext; + } + + public async Task Handle( + TRequest request, + Func> next, + CancellationToken cancellationToken + ) + { + using var _ = LogContext.PushProperty(LoggerPropertyName, _executionContext, true); + return await next(request, cancellationToken); + } +} diff --git a/src/ConductorSharp.Engine/Middlewares/RequestResponseLoggingBehavior.cs b/src/ConductorSharp.Engine/Middlewares/RequestResponseLoggingBehavior.cs new file mode 100644 index 00000000..1bd086f6 --- /dev/null +++ b/src/ConductorSharp.Engine/Middlewares/RequestResponseLoggingBehavior.cs @@ -0,0 +1,80 @@ +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; +using Microsoft.Extensions.Logging; + +namespace ConductorSharp.Engine.Middlewares; + +// TODO: Consider removing this +public class RequestResponseLoggingMiddleware : INgWorkerMiddleware + where TRequest : class, ITaskInput, new() +{ + private readonly ILogger> _logger; + private readonly ConductorSharpExecutionContext _context; + + public RequestResponseLoggingMiddleware( + ILogger> logger, + ConductorSharpExecutionContext context + ) + { + _logger = logger; + _context = context; + } + + public async Task Handle( + TRequest request, + Func> next, + CancellationToken cancellationToken + ) + { + var requestId = Guid.NewGuid(); + var requestName = typeof(TRequest).Name; + + var stopwatch = new Stopwatch(); + + _logger.LogInformation( + $"Submitting request {{Request}} with payload {{@{requestName}}} and with id {{RequestId}}", + requestName, + request, + requestId + ); + stopwatch.Start(); + + try + { + var response = await next(request, cancellationToken); + + stopwatch.Stop(); + + _logger.LogInformation( + $"Received response {{@Response}} for request {{Request}} with id {{RequestId}} (exec time = {{ElapsedMilliseconds}})", + response, + requestName, + requestId, + stopwatch.ElapsedMilliseconds + ); + + return response; + } + catch (OperationCanceledException) when (_context.TaskId != null) + { + // Simply rethrow and do not log in order for cancellation notifier to work + throw; + } + catch (Exception exc) + { + stopwatch.Stop(); + _logger.LogError( + $"Exception occured {{@Exception}} for request {{Request}} with id {{RequestId}} (exec time = {{ElapsedMilliseconds}})", + exc, + requestName, + requestId, + stopwatch.ElapsedMilliseconds + ); + throw; + } + } +} diff --git a/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs new file mode 100644 index 00000000..a49e635d --- /dev/null +++ b/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; + +namespace ConductorSharp.Engine.Middlewares; + +public class TaskExecutionTrackingMiddleware : INgWorkerMiddleware + where TRequest : class, ITaskInput, new() +{ + private readonly ConductorSharpExecutionContext _executionContext; + private readonly IEnumerable _taskExecutionServices; + + public TaskExecutionTrackingMiddleware(ConductorSharpExecutionContext executionContext, IEnumerable taskExecutionServices) + { + _executionContext = executionContext; + _taskExecutionServices = taskExecutionServices; + } + + public async Task Handle( + TRequest request, + Func> next, + CancellationToken cancellationToken + ) + { + var trackedTask = new RunningTask + { + TaskId = _executionContext.TaskId, + TaskName = _executionContext.TaskName, + StartedAt = DateTimeOffset.UtcNow + }; + + foreach (var taskExecutionService in _taskExecutionServices) + { + await taskExecutionService.OnPolled(trackedTask); + } + + try + { + var response = await next(request, cancellationToken); + + foreach (var taskExecutionService in _taskExecutionServices) + { + await taskExecutionService.OnCompleted(trackedTask); + } + + return response; + } + catch (Exception) + { + foreach (var taskExecutionService in _taskExecutionServices) + { + await taskExecutionService.OnFailed(trackedTask); + } + + throw; + } + } +} diff --git a/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs new file mode 100644 index 00000000..d2e5fe31 --- /dev/null +++ b/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs @@ -0,0 +1,22 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; + +namespace ConductorSharp.Engine.Middlewares; + +public class ValidationWorkerMiddleware : INgWorkerMiddleware + where TRequest : class, ITaskInput, new() +{ + public async Task Handle( + TRequest request, + Func> next, + CancellationToken cancellationToken + ) + { + ObjectValidator.Validate(request); + var response = await next(request, cancellationToken); + return response; + } +} From 5f49b6f613d018d7e3d576eb18aceb97d93eb0a1 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sat, 28 Jun 2025 16:27:10 +0200 Subject: [PATCH 09/35] Remove stopwatch --- src/ConductorSharp.Engine/Service/WorkerInvokerService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs index 9c9c350e..d7dc9de8 100644 --- a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs +++ b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs @@ -54,9 +54,7 @@ CancellationToken cancellationToken { var workerTypeInfo = new WorkerTypeInfo(workerType); var objRequest = SerializationHelper.DictonaryToObject(workerTypeInfo.RequestType, request, ConductorConstants.IoJsonSerializerSettings); - var sw = Stopwatch.StartNew(); var objResponse = await InternalInvoke(workerTypeInfo, objRequest, cancellationToken); - var t = sw.ElapsedMilliseconds; var response = SerializationHelper.ObjectToDictionary(objResponse, ConductorConstants.IoJsonSerializerSettings); return response; From 267a7591b98e59691934be2404a7f1d1e81f0883 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Wed, 2 Jul 2025 08:38:00 +0200 Subject: [PATCH 10/35] Specify proper outputData --- src/ConductorSharp.Engine/ExecutionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ConductorSharp.Engine/ExecutionManager.cs b/src/ConductorSharp.Engine/ExecutionManager.cs index c1cede5f..9ec04c80 100644 --- a/src/ConductorSharp.Engine/ExecutionManager.cs +++ b/src/ConductorSharp.Engine/ExecutionManager.cs @@ -187,7 +187,7 @@ await _taskManager.UpdateAsync( { TaskId = pollResponse.TaskId, Status = TaskResultStatus.COMPLETED, - OutputData = SerializationHelper.ObjectToDictionary(response, ConductorConstants.IoJsonSerializerSettings), + OutputData = response, WorkflowInstanceId = pollResponse.WorkflowInstanceId }, tokenHolder.CancellationToken From db8c82c9f425d319519dc6385c4bd3b0cbc6ff4b Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Wed, 2 Jul 2025 13:18:09 +0200 Subject: [PATCH 11/35] Replace RequestResponseLoggingBehavior with built in implementation --- .../Extensions/ServiceCollectionExtensions.cs | 1 - .../ConductorSharp.Definitions/Program.cs | 1 - examples/ConductorSharp.NoApi/Program.cs | 1 - src/ConductorSharp.Engine/ExecutionManager.cs | 22 ++++- .../Extensions/IPipelineBuilder.cs | 1 - .../Extensions/PipelineBuilder.cs | 3 - .../RequestResponseLoggingBehavior.cs | 80 ------------------- .../TypePollSpreadingExecutionManager.cs | 22 ++++- .../Integration/WorkflowBuilderTests.cs | 1 - .../Unit/TaskDefinitionBuilderTests.cs | 1 - 10 files changed, 42 insertions(+), 91 deletions(-) delete mode 100644 src/ConductorSharp.Engine/Middlewares/RequestResponseLoggingBehavior.cs diff --git a/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs b/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs index 9bb7414b..9359025b 100644 --- a/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs +++ b/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs @@ -23,7 +23,6 @@ public static IServiceCollection ConfigureApiEnabled(this IServiceCollection hos { pipelines.AddExecutionTaskTracking(); pipelines.AddContextLogging(); - pipelines.AddRequestResponseLogging(); pipelines.AddValidation(); }); diff --git a/examples/ConductorSharp.Definitions/Program.cs b/examples/ConductorSharp.Definitions/Program.cs index 9c2321d7..662b11a0 100644 --- a/examples/ConductorSharp.Definitions/Program.cs +++ b/examples/ConductorSharp.Definitions/Program.cs @@ -32,7 +32,6 @@ .AddPipelines(pipelines => { pipelines.AddCustomMiddleware(typeof(CustomMiddleware<,>)); - pipelines.AddRequestResponseLogging(); pipelines.AddValidation(); }) .AddCSharpLambdaTasks(); diff --git a/examples/ConductorSharp.NoApi/Program.cs b/examples/ConductorSharp.NoApi/Program.cs index a92f8ec7..8fcc6907 100644 --- a/examples/ConductorSharp.NoApi/Program.cs +++ b/examples/ConductorSharp.NoApi/Program.cs @@ -34,7 +34,6 @@ .AddPipelines(pipelines => { pipelines.AddContextLogging(); - pipelines.AddRequestResponseLogging(); pipelines.AddValidation(); pipelines.AddCustomMiddleware(); }) diff --git a/src/ConductorSharp.Engine/ExecutionManager.cs b/src/ConductorSharp.Engine/ExecutionManager.cs index 9ec04c80..927dd6ae 100644 --- a/src/ConductorSharp.Engine/ExecutionManager.cs +++ b/src/ConductorSharp.Engine/ExecutionManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; @@ -180,7 +181,25 @@ CancellationToken cancellationToken context.WorkerId = workerId; } + _logger.LogInformation( + "Executing worker {Worker} for task {Task}(id={TaskId}) as part of workflow {Workflow}(id={WorkflowId})", + scheduledWorker.TaskType.Name, + pollResponse.TaskDefName, + pollResponse.TaskId, + pollResponse.WorkflowType, + pollResponse.WorkflowInstanceId + ); + var stopwatch = Stopwatch.StartNew(); var response = await _workerInvokerService.Invoke(scheduledWorker.TaskType, pollResponse.InputData, tokenHolder.CancellationToken); + _logger.LogInformation( + "Worker {Worker} executed for task {Task}(id={TaskId}) as part of workflow {Workflow}(id={WorkflowId}), exec time = {WorkerPipelineExecutionTime}ms", + scheduledWorker.TaskType.Name, + pollResponse.TaskDefName, + pollResponse.TaskId, + pollResponse.WorkflowType, + pollResponse.WorkflowInstanceId, + stopwatch.ElapsedMilliseconds + ); await _taskManager.UpdateAsync( new TaskResult @@ -216,9 +235,10 @@ await _taskManager.UpdateAsync( catch (Exception exception) { _logger.LogError( - "{@Exception} while executing {Task} as part of {Workflow} with id {WorkflowId}", exception, + "Exception while processing polled task {Task}(id={TaskId}) as part of workflow {Workflow}(id={WorkflowId})", pollResponse.TaskDefName, + pollResponse.TaskId, pollResponse.WorkflowType, pollResponse.WorkflowInstanceId ); diff --git a/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs index 27e39b25..420b643d 100644 --- a/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs @@ -5,7 +5,6 @@ namespace ConductorSharp.Engine.Extensions { public interface IPipelineBuilder { - void AddRequestResponseLogging(); void AddValidation(); void AddContextLogging(); void AddExecutionTaskTracking(); diff --git a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs index cb9adcbc..3e27e66b 100644 --- a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs @@ -7,9 +7,6 @@ namespace ConductorSharp.Engine.Extensions; internal class PipelineBuilder(IServiceCollection serviceCollection) : IPipelineBuilder { - public void AddRequestResponseLogging() => - serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(RequestResponseLoggingMiddleware<,>)); - public void AddValidation() => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(ValidationWorkerMiddleware<,>)); public void AddContextLogging() => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(ContextLoggingMiddleware<,>)); diff --git a/src/ConductorSharp.Engine/Middlewares/RequestResponseLoggingBehavior.cs b/src/ConductorSharp.Engine/Middlewares/RequestResponseLoggingBehavior.cs deleted file mode 100644 index 1bd086f6..00000000 --- a/src/ConductorSharp.Engine/Middlewares/RequestResponseLoggingBehavior.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using ConductorSharp.Engine.Interface; -using ConductorSharp.Engine.Util; -using Microsoft.Extensions.Logging; - -namespace ConductorSharp.Engine.Middlewares; - -// TODO: Consider removing this -public class RequestResponseLoggingMiddleware : INgWorkerMiddleware - where TRequest : class, ITaskInput, new() -{ - private readonly ILogger> _logger; - private readonly ConductorSharpExecutionContext _context; - - public RequestResponseLoggingMiddleware( - ILogger> logger, - ConductorSharpExecutionContext context - ) - { - _logger = logger; - _context = context; - } - - public async Task Handle( - TRequest request, - Func> next, - CancellationToken cancellationToken - ) - { - var requestId = Guid.NewGuid(); - var requestName = typeof(TRequest).Name; - - var stopwatch = new Stopwatch(); - - _logger.LogInformation( - $"Submitting request {{Request}} with payload {{@{requestName}}} and with id {{RequestId}}", - requestName, - request, - requestId - ); - stopwatch.Start(); - - try - { - var response = await next(request, cancellationToken); - - stopwatch.Stop(); - - _logger.LogInformation( - $"Received response {{@Response}} for request {{Request}} with id {{RequestId}} (exec time = {{ElapsedMilliseconds}})", - response, - requestName, - requestId, - stopwatch.ElapsedMilliseconds - ); - - return response; - } - catch (OperationCanceledException) when (_context.TaskId != null) - { - // Simply rethrow and do not log in order for cancellation notifier to work - throw; - } - catch (Exception exc) - { - stopwatch.Stop(); - _logger.LogError( - $"Exception occured {{@Exception}} for request {{Request}} with id {{RequestId}} (exec time = {{ElapsedMilliseconds}})", - exc, - requestName, - requestId, - stopwatch.ElapsedMilliseconds - ); - throw; - } - } -} diff --git a/src/ConductorSharp.Engine/TypePollSpreadingExecutionManager.cs b/src/ConductorSharp.Engine/TypePollSpreadingExecutionManager.cs index 42e54b31..06ad732f 100644 --- a/src/ConductorSharp.Engine/TypePollSpreadingExecutionManager.cs +++ b/src/ConductorSharp.Engine/TypePollSpreadingExecutionManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; @@ -189,7 +190,25 @@ CancellationToken cancellationToken context.WorkerId = workerId; } + _logger.LogInformation( + "Executing worker {Worker} for task {Task}(id={TaskId}) as part of workflow {Workflow}(id={WorkflowId})", + scheduledWorker.TaskType.Name, + pollResponse.TaskDefName, + pollResponse.TaskId, + pollResponse.WorkflowType, + pollResponse.WorkflowInstanceId + ); + var stopwatch = Stopwatch.StartNew(); var response = await _workerInvokerService.Invoke(scheduledWorker.TaskType, pollResponse.InputData, tokenHolder.CancellationToken); + _logger.LogInformation( + "Worker {Worker} executed for task {Task}(id={TaskId}) as part of workflow {Workflow}(id={WorkflowId}), exec time = {WorkerPipelineExecutionTime}ms", + scheduledWorker.TaskType.Name, + pollResponse.TaskDefName, + pollResponse.TaskId, + pollResponse.WorkflowType, + pollResponse.WorkflowInstanceId, + stopwatch.ElapsedMilliseconds + ); await _taskManager.UpdateAsync( new TaskResult @@ -225,9 +244,10 @@ await _taskManager.UpdateAsync( catch (Exception exception) { _logger.LogError( - "{@Exception} while executing {Task} as part of {Workflow} with id {WorkflowId}", exception, + "Exception while processing polled task {Task}(id={TaskId}) as part of workflow {Workflow}(id={WorkflowId})", pollResponse.TaskDefName, + pollResponse.TaskId, pollResponse.WorkflowType, pollResponse.WorkflowInstanceId ); diff --git a/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs b/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs index 8ef5b365..77fc5e2a 100644 --- a/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs +++ b/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs @@ -317,7 +317,6 @@ private static IServiceProvider RegisterWorkflow() .AddPipelines(pipelines => { pipelines.AddContextLogging(); - pipelines.AddRequestResponseLogging(); pipelines.AddValidation(); }) .AddCSharpLambdaTasks("TEST"); diff --git a/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs b/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs index fc83eebe..2dc3bff9 100644 --- a/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs +++ b/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs @@ -21,7 +21,6 @@ public TaskDefinitionBuilderTests() .AddPipelines(pipelines => { pipelines.AddContextLogging(); - pipelines.AddRequestResponseLogging(); pipelines.AddValidation(); }); From a300e17c3b449304a0586798a5921378799efbd6 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Wed, 2 Jul 2025 13:21:00 +0200 Subject: [PATCH 12/35] Remove unused interface --- src/ConductorSharp.Engine/Interface/IWorker.cs | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 src/ConductorSharp.Engine/Interface/IWorker.cs diff --git a/src/ConductorSharp.Engine/Interface/IWorker.cs b/src/ConductorSharp.Engine/Interface/IWorker.cs deleted file mode 100644 index d1ec7707..00000000 --- a/src/ConductorSharp.Engine/Interface/IWorker.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace ConductorSharp.Engine.Interface -{ - public interface IWorker { } -} From 7b29cdab1b66b6d84d0b543ff05ee6fd753563f2 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Wed, 2 Jul 2025 15:46:50 +0200 Subject: [PATCH 13/35] Remove ContextLoggingMiddleware, inject context by default --- .../Extensions/ServiceCollectionExtensions.cs | 1 - .../Handlers/PrepareEmailHandler.cs | 6 +-- .../Middlewares/CustomMiddleware.cs | 2 + .../Handlers/EnumTaskHandler.cs | 3 +- .../Handlers/GetCustomerHandler.cs | 3 +- .../Handlers/PrepareEmailHandler.cs | 10 +++-- .../MIddlewares/PrepareEmailMiddleware.cs | 2 + examples/ConductorSharp.NoApi/Program.cs | 1 - .../ConductorSharp.NoApi/appsettings.json | 2 +- src/ConductorSharp.Engine/ExecutionManager.cs | 30 ++++++------- .../Extensions/ConductorSharpBuilder.cs | 2 +- .../Extensions/IPipelineBuilder.cs | 1 - .../Extensions/PipelineBuilder.cs | 2 - .../Interface/INgWorker.cs | 5 +-- .../Interface/INgWorkerMiddleware.cs | 8 +++- .../Middlewares/ContextLoggingMiddleware.cs | 30 ------------- .../TaskExecutionTrackingMiddleware.cs | 5 ++- .../Middlewares/ValidationWorkerMiddleware.cs | 1 + src/ConductorSharp.Engine/NgWorker.cs | 3 +- .../Service/WorkerInvokerService.cs | 44 ++++++++++++++----- .../TypePollSpreadingExecutionManager.cs | 30 ++++++------- .../Util/ConductorSharpExecutionContext.cs | 17 ------- .../Util/WorkerExecutionContext.cs | 11 +++++ .../Tasks/CSharpLambdaTask.cs | 2 +- .../Tasks/ReadWorkflowTasks.cs | 6 ++- .../Tasks/WaitSeconds.cs | 3 +- .../Integration/UtilityTests.cs | 11 ++++- .../Integration/WorkflowBuilderTests.cs | 1 - .../Samples/Workers/GetCustomerHandler.cs | 7 ++- .../Samples/Workers/PrepareEmailHandler.cs | 7 ++- .../Unit/TaskDefinitionBuilderTests.cs | 1 - 31 files changed, 136 insertions(+), 121 deletions(-) delete mode 100644 src/ConductorSharp.Engine/Middlewares/ContextLoggingMiddleware.cs delete mode 100644 src/ConductorSharp.Engine/Util/ConductorSharpExecutionContext.cs create mode 100644 src/ConductorSharp.Engine/Util/WorkerExecutionContext.cs diff --git a/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs b/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs index 9359025b..4648882e 100644 --- a/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs +++ b/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs @@ -22,7 +22,6 @@ public static IServiceCollection ConfigureApiEnabled(this IServiceCollection hos .AddPipelines(pipelines => { pipelines.AddExecutionTaskTracking(); - pipelines.AddContextLogging(); pipelines.AddValidation(); }); diff --git a/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs b/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs index 1425b456..65eb413d 100644 --- a/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs +++ b/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs @@ -19,16 +19,16 @@ public class PrepareEmailResponse [OriginalName("EMAIL_prepare")] public class PrepareEmailHandler : INgWorker { - private readonly ConductorSharpExecutionContext _context; + private readonly WorkerExecutionContext _context; private readonly ILogger _logger; - public PrepareEmailHandler(ConductorSharpExecutionContext context, ILogger logger) + public PrepareEmailHandler(WorkerExecutionContext context, ILogger logger) { _context = context; _logger = logger; } - public async Task Handle(PrepareEmailRequest request, CancellationToken cancellationToken) + public async Task Handle(PrepareEmailRequest request, WorkerExecutionContext context, CancellationToken cancellationToken) { var emailBodyBuilder = new StringBuilder(); diff --git a/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs b/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs index f554555f..996c8b17 100644 --- a/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs +++ b/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs @@ -1,4 +1,5 @@ using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; using Microsoft.Extensions.Logging; namespace ConductorSharp.Definitions.Middlewares; @@ -15,6 +16,7 @@ public CustomMiddleware(ILogger> logger) public async Task Handle( TRequest request, + WorkerExecutionContext context, Func> next, CancellationToken cancellationToken ) diff --git a/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs b/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs index 198dd2a3..c7a4aaa8 100644 --- a/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs +++ b/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs @@ -1,6 +1,7 @@ using ConductorSharp.Client.Generated; using ConductorSharp.Engine.Builders.Metadata; using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; namespace ConductorSharp.NoApi.Handlers { @@ -17,7 +18,7 @@ public class EnumTaskOutput [OriginalName("ENUM_task")] public class EnumTaskHandler : INgWorker { - public Task Handle(EnumTaskInput request, CancellationToken cancellationToken) + public Task Handle(EnumTaskInput request, WorkerExecutionContext context, CancellationToken cancellationToken) { Console.WriteLine(request.Status); return System.Threading.Tasks.Task.FromResult(new EnumTaskOutput() { Status = request.Status }); diff --git a/examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs b/examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs index e713c643..5b44fb2b 100644 --- a/examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs +++ b/examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs @@ -1,6 +1,7 @@ using System.ComponentModel.DataAnnotations; using ConductorSharp.Engine.Builders.Metadata; using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; namespace ConductorSharp.NoApi.Handlers; @@ -36,7 +37,7 @@ public class GetCustomerHandler : INgWorker Handle(GetCustomerRequest request, CancellationToken cancellationToken) + public Task Handle(GetCustomerRequest request, WorkerExecutionContext context, CancellationToken cancellationToken) { var customer = customers.First(a => a.Id == request.CustomerId); diff --git a/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs b/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs index cf258ab2..9d3c5bdd 100644 --- a/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs +++ b/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs @@ -20,16 +20,20 @@ public class PrepareEmailResponse [OriginalName("EMAIL_prepare")] public class PrepareEmailHandler : INgWorker { - private readonly ConductorSharpExecutionContext _context; + private readonly WorkerExecutionContext _context; private readonly ILogger _logger; - public PrepareEmailHandler(ConductorSharpExecutionContext context, ILogger logger) + public PrepareEmailHandler(WorkerExecutionContext context, ILogger logger) { _context = context; _logger = logger; } - public async Task Handle(PrepareEmailRequest request, CancellationToken cancellationToken) + public async Task Handle( + PrepareEmailRequest request, + WorkerExecutionContext context, + CancellationToken cancellationToken + ) { var emailBodyBuilder = new StringBuilder(); diff --git a/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs b/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs index 2f436044..c0b6eae0 100644 --- a/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs +++ b/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs @@ -1,4 +1,5 @@ using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; using ConductorSharp.NoApi.Handlers; using Microsoft.Extensions.Logging; @@ -15,6 +16,7 @@ public PrepareEmailMiddleware(ILogger logger) public async Task Handle( PrepareEmailRequest request, + WorkerExecutionContext context, Func> next, CancellationToken cancellationToken ) diff --git a/examples/ConductorSharp.NoApi/Program.cs b/examples/ConductorSharp.NoApi/Program.cs index 8fcc6907..11894707 100644 --- a/examples/ConductorSharp.NoApi/Program.cs +++ b/examples/ConductorSharp.NoApi/Program.cs @@ -33,7 +33,6 @@ .SetHealthCheckService() .AddPipelines(pipelines => { - pipelines.AddContextLogging(); pipelines.AddValidation(); pipelines.AddCustomMiddleware(); }) diff --git a/examples/ConductorSharp.NoApi/appsettings.json b/examples/ConductorSharp.NoApi/appsettings.json index 0e2c41ba..617dd0a2 100644 --- a/examples/ConductorSharp.NoApi/appsettings.json +++ b/examples/ConductorSharp.NoApi/appsettings.json @@ -3,7 +3,7 @@ "BaseUrl": "http://localhost:48081", "LongPollInterval": 100, "MaxConcurrentWorkers": 10, - "SleepInterval": 500, + "SleepInterval": 2000, "KafkaCancellationNotifier": { "BootstrapServers": "localhost:29092", "GroupId": "ConductorSharp.NoApi", diff --git a/src/ConductorSharp.Engine/ExecutionManager.cs b/src/ConductorSharp.Engine/ExecutionManager.cs index 927dd6ae..3e2066a7 100644 --- a/src/ConductorSharp.Engine/ExecutionManager.cs +++ b/src/ConductorSharp.Engine/ExecutionManager.cs @@ -166,20 +166,15 @@ CancellationToken cancellationToken ); } - using var scope = _lifetimeScopeFactory.CreateScope(); - - var context = scope.ServiceProvider.GetService(); - - if (context != null) - { - context.WorkflowName = pollResponse.WorkflowType; - context.TaskName = pollResponse.TaskDefName; - context.TaskReferenceName = pollResponse.ReferenceTaskName; - context.WorkflowId = pollResponse.WorkflowInstanceId; - context.CorrelationId = pollResponse.CorrelationId; - context.TaskId = pollResponse.TaskId; - context.WorkerId = workerId; - } + var context = new WorkerExecutionContext( + WorkflowName: pollResponse.WorkflowType, + WorkflowId: pollResponse.WorkflowInstanceId, + TaskName: pollResponse.TaskDefName, + TaskId: pollResponse.TaskId, + TaskReferenceName: pollResponse.ReferenceTaskName, + CorrelationId: pollResponse.CorrelationId, + WorkerId: workerId + ); _logger.LogInformation( "Executing worker {Worker} for task {Task}(id={TaskId}) as part of workflow {Workflow}(id={WorkflowId})", @@ -190,7 +185,12 @@ CancellationToken cancellationToken pollResponse.WorkflowInstanceId ); var stopwatch = Stopwatch.StartNew(); - var response = await _workerInvokerService.Invoke(scheduledWorker.TaskType, pollResponse.InputData, tokenHolder.CancellationToken); + var response = await _workerInvokerService.Invoke( + scheduledWorker.TaskType, + pollResponse.InputData, + context, + tokenHolder.CancellationToken + ); _logger.LogInformation( "Worker {Worker} executed for task {Task}(id={TaskId}) as part of workflow {Workflow}(id={WorkflowId}), exec time = {WorkerPipelineExecutionTime}ms", scheduledWorker.TaskType.Name, diff --git a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs index e009cbbc..e1c8680c 100644 --- a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs @@ -37,7 +37,7 @@ public IExecutionManagerBuilder AddExecutionManager(int maxConcurrentWorkers, in Builder.AddSingleton(); - Builder.AddScoped(); + Builder.AddScoped(); Builder.AddSingleton(); diff --git a/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs index 420b643d..98075fed 100644 --- a/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs @@ -6,7 +6,6 @@ namespace ConductorSharp.Engine.Extensions public interface IPipelineBuilder { void AddValidation(); - void AddContextLogging(); void AddExecutionTaskTracking(); void AddCustomMiddleware(Type middlewareType); diff --git a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs index 3e27e66b..bfa1bfc8 100644 --- a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs @@ -9,8 +9,6 @@ internal class PipelineBuilder(IServiceCollection serviceCollection) : IPipeline { public void AddValidation() => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(ValidationWorkerMiddleware<,>)); - public void AddContextLogging() => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(ContextLoggingMiddleware<,>)); - public void AddExecutionTaskTracking() => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(TaskExecutionTrackingMiddleware<,>)); diff --git a/src/ConductorSharp.Engine/Interface/INgWorker.cs b/src/ConductorSharp.Engine/Interface/INgWorker.cs index 8d8ab82c..25d99fa8 100644 --- a/src/ConductorSharp.Engine/Interface/INgWorker.cs +++ b/src/ConductorSharp.Engine/Interface/INgWorker.cs @@ -1,5 +1,4 @@ -using System; -using System.Threading; +using System.Threading; using System.Threading.Tasks; using ConductorSharp.Engine.Util; @@ -8,5 +7,5 @@ namespace ConductorSharp.Engine.Interface; public interface INgWorker where TRequest : class, ITaskInput, new() { - Task Handle(TRequest test, CancellationToken cancellationToken); + Task Handle(TRequest test, WorkerExecutionContext context, CancellationToken cancellationToken); } diff --git a/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs b/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs index 6032b6d8..d63f1e58 100644 --- a/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs +++ b/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs @@ -1,11 +1,17 @@ using System; using System.Threading; using System.Threading.Tasks; +using ConductorSharp.Engine.Util; namespace ConductorSharp.Engine.Interface; public interface INgWorkerMiddleware where TRequest : class, ITaskInput, new() { - Task Handle(TRequest request, Func> next, CancellationToken cancellationToken); + Task Handle( + TRequest request, + WorkerExecutionContext context, + Func> next, + CancellationToken cancellationToken + ); } diff --git a/src/ConductorSharp.Engine/Middlewares/ContextLoggingMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/ContextLoggingMiddleware.cs deleted file mode 100644 index a2bbf9dd..00000000 --- a/src/ConductorSharp.Engine/Middlewares/ContextLoggingMiddleware.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using ConductorSharp.Engine.Interface; -using ConductorSharp.Engine.Util; -using Serilog.Context; - -namespace ConductorSharp.Engine.Middlewares; - -public class ContextLoggingMiddleware : INgWorkerMiddleware - where TRequest : class, ITaskInput, new() -{ - private readonly ConductorSharpExecutionContext _executionContext; - private const string LoggerPropertyName = "ConductorContext"; - - public ContextLoggingMiddleware(ConductorSharpExecutionContext executionContext) - { - _executionContext = executionContext; - } - - public async Task Handle( - TRequest request, - Func> next, - CancellationToken cancellationToken - ) - { - using var _ = LogContext.PushProperty(LoggerPropertyName, _executionContext, true); - return await next(request, cancellationToken); - } -} diff --git a/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs index a49e635d..8efc4010 100644 --- a/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs +++ b/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs @@ -10,10 +10,10 @@ namespace ConductorSharp.Engine.Middlewares; public class TaskExecutionTrackingMiddleware : INgWorkerMiddleware where TRequest : class, ITaskInput, new() { - private readonly ConductorSharpExecutionContext _executionContext; + private readonly WorkerExecutionContext _executionContext; private readonly IEnumerable _taskExecutionServices; - public TaskExecutionTrackingMiddleware(ConductorSharpExecutionContext executionContext, IEnumerable taskExecutionServices) + public TaskExecutionTrackingMiddleware(WorkerExecutionContext executionContext, IEnumerable taskExecutionServices) { _executionContext = executionContext; _taskExecutionServices = taskExecutionServices; @@ -21,6 +21,7 @@ public TaskExecutionTrackingMiddleware(ConductorSharpExecutionContext executionC public async Task Handle( TRequest request, + WorkerExecutionContext context, Func> next, CancellationToken cancellationToken ) diff --git a/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs index d2e5fe31..6964e9dd 100644 --- a/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs +++ b/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs @@ -11,6 +11,7 @@ public class ValidationWorkerMiddleware : INgWorkerMiddlewa { public async Task Handle( TRequest request, + WorkerExecutionContext context, Func> next, CancellationToken cancellationToken ) diff --git a/src/ConductorSharp.Engine/NgWorker.cs b/src/ConductorSharp.Engine/NgWorker.cs index 0182c512..5495f3f8 100644 --- a/src/ConductorSharp.Engine/NgWorker.cs +++ b/src/ConductorSharp.Engine/NgWorker.cs @@ -2,11 +2,12 @@ using System.Threading.Tasks; using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; +using ConductorSharp.Engine.Util; namespace ConductorSharp.Engine; public abstract class NgWorker : SimpleTaskModel, INgWorker where TRequest : class, ITaskInput, new() { - public abstract Task Handle(TRequest test, CancellationToken cancellationToken); + public abstract Task Handle(TRequest test, WorkerExecutionContext context, CancellationToken cancellationToken); } diff --git a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs index d7dc9de8..9fb6b4bb 100644 --- a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs +++ b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs @@ -49,22 +49,28 @@ public WorkerTypeInfo(Type workerType) public async Task> Invoke( Type workerType, IDictionary request, + WorkerExecutionContext workerExecutionContext, CancellationToken cancellationToken ) { var workerTypeInfo = new WorkerTypeInfo(workerType); var objRequest = SerializationHelper.DictonaryToObject(workerTypeInfo.RequestType, request, ConductorConstants.IoJsonSerializerSettings); - var objResponse = await InternalInvoke(workerTypeInfo, objRequest, cancellationToken); + var objResponse = await InternalInvoke(workerTypeInfo, objRequest, workerExecutionContext, cancellationToken); var response = SerializationHelper.ObjectToDictionary(objResponse, ConductorConstants.IoJsonSerializerSettings); return response; } - private async Task InternalInvoke(WorkerTypeInfo workerTypeInfo, object request, CancellationToken cancellationToken) + private async Task InternalInvoke( + WorkerTypeInfo workerTypeInfo, + object request, + WorkerExecutionContext context, + CancellationToken cancellationToken + ) { var middlewares = _serviceProvider.GetServices(workerTypeInfo.MiddlewareType).ToArray(); var worker = _serviceProvider.GetRequiredService(workerTypeInfo.WorkerType); - var resultTask = InvokeMiddlewarePipeline(middlewares, worker, workerTypeInfo, request, cancellationToken); + var resultTask = InvokeMiddlewarePipeline(middlewares, worker, workerTypeInfo, request, context, cancellationToken); await resultTask; var result = workerTypeInfo.TaskResultProperty.GetValue(resultTask); return result; @@ -75,44 +81,60 @@ private static Task InvokeMiddlewarePipeline( object worker, WorkerTypeInfo workerTypeInfo, object request, + WorkerExecutionContext context, CancellationToken cancellationToken ) { object result; if (middlewares.Length == 0) - result = workerTypeInfo.WorkerHandleMethod.Invoke(worker, [request, cancellationToken]); + result = workerTypeInfo.WorkerHandleMethod.Invoke(worker, [request, context, cancellationToken]); else { - var next = GenerateCallToMiddleware(middlewares, worker, 1, workerTypeInfo).Compile(); - result = workerTypeInfo.MiddlewareHandleMethod.Invoke(middlewares[0], [request, next, cancellationToken]); + var next = GenerateCallToMiddleware(middlewares, worker, 1, workerTypeInfo, context).Compile(); + result = workerTypeInfo.MiddlewareHandleMethod.Invoke(middlewares[0], [request, context, next, cancellationToken]); } return (Task)result; } - private static LambdaExpression GenerateCallToHandler(object worker, WorkerTypeInfo workerInfo) + private static LambdaExpression GenerateCallToHandler(object worker, WorkerTypeInfo workerInfo, WorkerExecutionContext context) { var requestParam = Expression.Parameter(workerInfo.RequestType); var cancellationTokenParam = Expression.Parameter(typeof(CancellationToken)); + var contextParam = Expression.Constant(context); - var lambdaBody = Expression.Call(Expression.Constant(worker), workerInfo.WorkerHandleMethod, requestParam, cancellationTokenParam); + var lambdaBody = Expression.Call( + Expression.Constant(worker), + workerInfo.WorkerHandleMethod, + requestParam, + contextParam, + cancellationTokenParam + ); var lambda = Expression.Lambda(workerInfo.NextFuncType, lambdaBody, requestParam, cancellationTokenParam); return lambda; } - private static LambdaExpression GenerateCallToMiddleware(object[] middlewares, object worker, int middlewareIndex, WorkerTypeInfo workerInfo) + private static LambdaExpression GenerateCallToMiddleware( + object[] middlewares, + object worker, + int middlewareIndex, + WorkerTypeInfo workerInfo, + WorkerExecutionContext context + ) { if (middlewares.Length == middlewareIndex) - return GenerateCallToHandler(worker, workerInfo); + return GenerateCallToHandler(worker, workerInfo, context); var requestParam = Expression.Parameter(workerInfo.RequestType); var cancellationTokenParam = Expression.Parameter(typeof(CancellationToken)); + var contextParam = Expression.Constant(context); - var nextLambda = GenerateCallToMiddleware(middlewares, worker, middlewareIndex + 1, workerInfo); + var nextLambda = GenerateCallToMiddleware(middlewares, worker, middlewareIndex + 1, workerInfo, context); var lambdaBody = Expression.Call( Expression.Constant(middlewares[middlewareIndex]), workerInfo.MiddlewareHandleMethod, requestParam, + contextParam, nextLambda, cancellationTokenParam ); diff --git a/src/ConductorSharp.Engine/TypePollSpreadingExecutionManager.cs b/src/ConductorSharp.Engine/TypePollSpreadingExecutionManager.cs index 06ad732f..7021a31f 100644 --- a/src/ConductorSharp.Engine/TypePollSpreadingExecutionManager.cs +++ b/src/ConductorSharp.Engine/TypePollSpreadingExecutionManager.cs @@ -175,20 +175,15 @@ CancellationToken cancellationToken ); } - using var scope = _lifetimeScopeFactory.CreateScope(); - - var context = scope.ServiceProvider.GetService(); - - if (context != null) - { - context.WorkflowName = pollResponse.WorkflowType; - context.TaskName = pollResponse.TaskDefName; - context.TaskReferenceName = pollResponse.ReferenceTaskName; - context.WorkflowId = pollResponse.WorkflowInstanceId; - context.CorrelationId = pollResponse.CorrelationId; - context.TaskId = pollResponse.TaskId; - context.WorkerId = workerId; - } + var context = new WorkerExecutionContext( + WorkflowName: pollResponse.WorkflowType, + WorkflowId: pollResponse.WorkflowInstanceId, + TaskName: pollResponse.TaskDefName, + TaskId: pollResponse.TaskId, + TaskReferenceName: pollResponse.ReferenceTaskName, + CorrelationId: pollResponse.CorrelationId, + WorkerId: workerId + ); _logger.LogInformation( "Executing worker {Worker} for task {Task}(id={TaskId}) as part of workflow {Workflow}(id={WorkflowId})", @@ -199,7 +194,12 @@ CancellationToken cancellationToken pollResponse.WorkflowInstanceId ); var stopwatch = Stopwatch.StartNew(); - var response = await _workerInvokerService.Invoke(scheduledWorker.TaskType, pollResponse.InputData, tokenHolder.CancellationToken); + var response = await _workerInvokerService.Invoke( + scheduledWorker.TaskType, + pollResponse.InputData, + context, + tokenHolder.CancellationToken + ); _logger.LogInformation( "Worker {Worker} executed for task {Task}(id={TaskId}) as part of workflow {Workflow}(id={WorkflowId}), exec time = {WorkerPipelineExecutionTime}ms", scheduledWorker.TaskType.Name, diff --git a/src/ConductorSharp.Engine/Util/ConductorSharpExecutionContext.cs b/src/ConductorSharp.Engine/Util/ConductorSharpExecutionContext.cs deleted file mode 100644 index 91f30f9b..00000000 --- a/src/ConductorSharp.Engine/Util/ConductorSharpExecutionContext.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ConductorSharp.Engine.Util -{ - public class ConductorSharpExecutionContext - { - public string WorkflowName { get; set; } - public string WorkflowId { get; set; } - public string TaskName { get; set; } - public string TaskId { get; set; } - public string TaskReferenceName { get; set; } - public string CorrelationId { get; set; } - public string WorkerId { get; set; } - } -} diff --git a/src/ConductorSharp.Engine/Util/WorkerExecutionContext.cs b/src/ConductorSharp.Engine/Util/WorkerExecutionContext.cs new file mode 100644 index 00000000..7eb65e73 --- /dev/null +++ b/src/ConductorSharp.Engine/Util/WorkerExecutionContext.cs @@ -0,0 +1,11 @@ +namespace ConductorSharp.Engine.Util; + +public record WorkerExecutionContext( + string WorkflowName, + string WorkflowId, + string TaskName, + string TaskId, + string TaskReferenceName, + string CorrelationId, + string WorkerId +); diff --git a/src/ConductorSharp.Patterns/Tasks/CSharpLambdaTask.cs b/src/ConductorSharp.Patterns/Tasks/CSharpLambdaTask.cs index 32188a47..c40dcd45 100644 --- a/src/ConductorSharp.Patterns/Tasks/CSharpLambdaTask.cs +++ b/src/ConductorSharp.Patterns/Tasks/CSharpLambdaTask.cs @@ -37,7 +37,7 @@ internal class CSharpLambdaTask(WorkflowBuildItemRegistry itemRegistry) : INgWor private readonly WorkflowBuildItemRegistry _itemRegistry = itemRegistry; - public Task Handle(CSharpLambdaTaskInput request, CancellationToken cancellationToken) + public Task Handle(CSharpLambdaTaskInput request, WorkerExecutionContext context, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(request.LambdaIdentifier)) { diff --git a/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs b/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs index 9cbe3569..a2f80465 100644 --- a/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs +++ b/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs @@ -39,7 +39,11 @@ public class ReadWorkflowTasks(IWorkflowService workflowService) : NgWorker Handle(ReadWorkflowTasksRequest input, CancellationToken cancellationToken) + public override async Task Handle( + ReadWorkflowTasksRequest input, + WorkerExecutionContext context, + CancellationToken cancellationToken + ) { if (string.IsNullOrEmpty(input.TaskNames)) { diff --git a/src/ConductorSharp.Patterns/Tasks/WaitSeconds.cs b/src/ConductorSharp.Patterns/Tasks/WaitSeconds.cs index 76f6a51a..5c03ac6d 100644 --- a/src/ConductorSharp.Patterns/Tasks/WaitSeconds.cs +++ b/src/ConductorSharp.Patterns/Tasks/WaitSeconds.cs @@ -5,6 +5,7 @@ using ConductorSharp.Engine.Builders.Metadata; using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Model; +using ConductorSharp.Engine.Util; namespace ConductorSharp.Patterns.Tasks { @@ -24,7 +25,7 @@ public class WaitSecondsRequest : ITaskInput [OriginalName(Constants.TaskNamePrefix + "_wait_seconds")] public class WaitSeconds : NgWorker { - public override async Task Handle(WaitSecondsRequest input, CancellationToken cancellationToken) + public override async Task Handle(WaitSecondsRequest input, WorkerExecutionContext context, CancellationToken cancellationToken) { await Task.Delay(input.Seconds * 1000, cancellationToken); return new NoOutput(); diff --git a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs index 6b4213fd..f6265481 100644 --- a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs +++ b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs @@ -26,7 +26,7 @@ public class Response { } public class Handler : INgWorker { - public Task Handle(Request request, CancellationToken cancellationToken) + public Task Handle(Request request, WorkerExecutionContext context, CancellationToken cancellationToken) { return Task.FromResult(new Response()); } @@ -37,6 +37,7 @@ public class Middleware : INgWorkerMiddleware { public async Task Handle( Request request, + WorkerExecutionContext context, Func> next, CancellationToken cancellationToken ) @@ -50,6 +51,7 @@ public class GenericMiddleware : INgWorkerMiddleware Handle( TRequest request, + WorkerExecutionContext context, Func> next, CancellationToken cancellationToken ) @@ -72,7 +74,12 @@ public async Task Test() for (int i = 0; i < 5; i++) { var sw = Stopwatch.StartNew(); - var result = await invoker.Invoke(typeof(Request.Handler), new Dictionary(), default); + var result = await invoker.Invoke( + typeof(Request.Handler), + new Dictionary(), + new WorkerExecutionContext(WorkflowName: "test", WorkflowId: null, "", "", "", "", ""), + default + ); var t = sw.ElapsedMilliseconds; } } diff --git a/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs b/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs index 77fc5e2a..c2dbecb6 100644 --- a/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs +++ b/test/ConductorSharp.Engine.Tests/Integration/WorkflowBuilderTests.cs @@ -316,7 +316,6 @@ private static IServiceProvider RegisterWorkflow() .AddExecutionManager(10, 100, 100, null) .AddPipelines(pipelines => { - pipelines.AddContextLogging(); pipelines.AddValidation(); }) .AddCSharpLambdaTasks("TEST"); diff --git a/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs b/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs index e25c1af8..c94cbe56 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs @@ -26,6 +26,9 @@ public class Customer [OriginalName("CUSTOMER_get")] public class GetCustomerHandler : NgWorker { - public override Task Handle(GetCustomerRequest request, CancellationToken cancellationToken) => - throw new NotImplementedException(); + public override Task Handle( + GetCustomerRequest request, + WorkerExecutionContext context, + CancellationToken cancellationToken + ) => throw new NotImplementedException(); } diff --git a/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs b/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs index 1c2ad582..8c3e556c 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs @@ -16,6 +16,9 @@ public class PrepareEmailResponse [OriginalName("EMAIL_prepare")] public class PrepareEmailHandler : NgWorker { - public override Task Handle(PrepareEmailRequest request, CancellationToken cancellationToken) => - throw new NotImplementedException(); + public override Task Handle( + PrepareEmailRequest request, + WorkerExecutionContext context, + CancellationToken cancellationToken + ) => throw new NotImplementedException(); } diff --git a/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs b/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs index 2dc3bff9..88411a3a 100644 --- a/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs +++ b/test/ConductorSharp.Engine.Tests/Unit/TaskDefinitionBuilderTests.cs @@ -20,7 +20,6 @@ public TaskDefinitionBuilderTests() .AddExecutionManager(10, 100, 100, null) .AddPipelines(pipelines => { - pipelines.AddContextLogging(); pipelines.AddValidation(); }); From 98e1433496780853839911bffa46187261ff1b5f Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Wed, 2 Jul 2025 16:11:53 +0200 Subject: [PATCH 14/35] Make next delegate parameterless --- .../Middlewares/CustomMiddleware.cs | 4 +- .../MIddlewares/PrepareEmailMiddleware.cs | 4 +- .../Interface/INgWorkerMiddleware.cs | 7 +-- .../TaskExecutionTrackingMiddleware.cs | 4 +- .../Middlewares/ValidationWorkerMiddleware.cs | 4 +- .../Service/WorkerInvokerService.cs | 46 +++++++++++-------- .../Integration/UtilityTests.cs | 12 +++-- 7 files changed, 43 insertions(+), 38 deletions(-) diff --git a/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs b/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs index 996c8b17..e54e9166 100644 --- a/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs +++ b/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs @@ -17,12 +17,12 @@ public CustomMiddleware(ILogger> logger) public async Task Handle( TRequest request, WorkerExecutionContext context, - Func> next, + Func> next, CancellationToken cancellationToken ) { _logger.LogInformation("Executed before all middlewares"); - var response = await next(request, cancellationToken); + var response = await next(); _logger.LogInformation("Executed after all middlewares"); return response; } diff --git a/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs b/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs index c0b6eae0..b7efb10c 100644 --- a/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs +++ b/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs @@ -17,12 +17,12 @@ public PrepareEmailMiddleware(ILogger logger) public async Task Handle( PrepareEmailRequest request, WorkerExecutionContext context, - Func> next, + Func> next, CancellationToken cancellationToken ) { _logger.LogInformation($"Executed only before {nameof(PrepareEmailHandler)}"); - var response = await next(request, cancellationToken); + var response = await next(); _logger.LogInformation($"Executed only after {nameof(PrepareEmailHandler)}"); return response; } diff --git a/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs b/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs index d63f1e58..6e0ace81 100644 --- a/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs +++ b/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs @@ -8,10 +8,5 @@ namespace ConductorSharp.Engine.Interface; public interface INgWorkerMiddleware where TRequest : class, ITaskInput, new() { - Task Handle( - TRequest request, - WorkerExecutionContext context, - Func> next, - CancellationToken cancellationToken - ); + Task Handle(TRequest request, WorkerExecutionContext context, Func> next, CancellationToken cancellationToken); } diff --git a/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs index 8efc4010..ece3ee76 100644 --- a/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs +++ b/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs @@ -22,7 +22,7 @@ public TaskExecutionTrackingMiddleware(WorkerExecutionContext executionContext, public async Task Handle( TRequest request, WorkerExecutionContext context, - Func> next, + Func> next, CancellationToken cancellationToken ) { @@ -40,7 +40,7 @@ CancellationToken cancellationToken try { - var response = await next(request, cancellationToken); + var response = await next(); foreach (var taskExecutionService in _taskExecutionServices) { diff --git a/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs index 6964e9dd..fb4aa14f 100644 --- a/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs +++ b/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs @@ -12,12 +12,12 @@ public class ValidationWorkerMiddleware : INgWorkerMiddlewa public async Task Handle( TRequest request, WorkerExecutionContext context, - Func> next, + Func> next, CancellationToken cancellationToken ) { ObjectValidator.Validate(request); - var response = await next(request, cancellationToken); + var response = await next(); return response; } } diff --git a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs index 9fb6b4bb..580581b0 100644 --- a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs +++ b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs @@ -90,55 +90,63 @@ CancellationToken cancellationToken result = workerTypeInfo.WorkerHandleMethod.Invoke(worker, [request, context, cancellationToken]); else { - var next = GenerateCallToMiddleware(middlewares, worker, 1, workerTypeInfo, context).Compile(); + var next = GenerateCallToMiddleware(middlewares, worker, request, 1, workerTypeInfo, context, cancellationToken).Compile(); result = workerTypeInfo.MiddlewareHandleMethod.Invoke(middlewares[0], [request, context, next, cancellationToken]); } return (Task)result; } - private static LambdaExpression GenerateCallToHandler(object worker, WorkerTypeInfo workerInfo, WorkerExecutionContext context) + private static LambdaExpression GenerateCallToHandler( + object worker, + object request, + WorkerTypeInfo workerInfo, + WorkerExecutionContext context, + CancellationToken cancellationToken + ) { - var requestParam = Expression.Parameter(workerInfo.RequestType); - var cancellationTokenParam = Expression.Parameter(typeof(CancellationToken)); - var contextParam = Expression.Constant(context); + var requestArgument = Expression.Constant(request); + var cancellationTokenArgument = Expression.Constant(cancellationToken); + var contextArgument = Expression.Constant(context); var lambdaBody = Expression.Call( Expression.Constant(worker), workerInfo.WorkerHandleMethod, - requestParam, - contextParam, - cancellationTokenParam + requestArgument, + contextArgument, + cancellationTokenArgument ); - var lambda = Expression.Lambda(workerInfo.NextFuncType, lambdaBody, requestParam, cancellationTokenParam); + var lambda = Expression.Lambda(workerInfo.NextFuncType, lambdaBody); return lambda; } private static LambdaExpression GenerateCallToMiddleware( object[] middlewares, object worker, + object request, int middlewareIndex, WorkerTypeInfo workerInfo, - WorkerExecutionContext context + WorkerExecutionContext context, + CancellationToken cancellationToken ) { if (middlewares.Length == middlewareIndex) - return GenerateCallToHandler(worker, workerInfo, context); + return GenerateCallToHandler(worker, request, workerInfo, context, cancellationToken); - var requestParam = Expression.Parameter(workerInfo.RequestType); - var cancellationTokenParam = Expression.Parameter(typeof(CancellationToken)); - var contextParam = Expression.Constant(context); + var requestArgument = Expression.Constant(request); + var cancellationTokenArgument = Expression.Constant(cancellationToken); + var contextArgument = Expression.Constant(context); - var nextLambda = GenerateCallToMiddleware(middlewares, worker, middlewareIndex + 1, workerInfo, context); + var nextLambda = GenerateCallToMiddleware(middlewares, worker, request, middlewareIndex + 1, workerInfo, context, cancellationToken); var lambdaBody = Expression.Call( Expression.Constant(middlewares[middlewareIndex]), workerInfo.MiddlewareHandleMethod, - requestParam, - contextParam, + requestArgument, + contextArgument, nextLambda, - cancellationTokenParam + cancellationTokenArgument ); - var lambda = Expression.Lambda(workerInfo.NextFuncType, lambdaBody, requestParam, cancellationTokenParam); + var lambda = Expression.Lambda(workerInfo.NextFuncType, lambdaBody); return lambda; } } diff --git a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs index f6265481..db603e2c 100644 --- a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs +++ b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs @@ -22,6 +22,8 @@ public void NamingUtilShouldReturnCorrectNameableObjectName() public class Request : ITaskInput { + public string Baba { get; set; } = "Baba"; + public class Response { } public class Handler : INgWorker @@ -38,11 +40,11 @@ public class Middleware : INgWorkerMiddleware public async Task Handle( Request request, WorkerExecutionContext context, - Func> next, + Func> next, CancellationToken cancellationToken ) { - return await next(request, cancellationToken); + return await next(); } } @@ -52,11 +54,11 @@ public class GenericMiddleware : INgWorkerMiddleware Handle( TRequest request, WorkerExecutionContext context, - Func> next, + Func> next, CancellationToken cancellationToken ) { - return await next(request, cancellationToken); + return await next(); } } @@ -78,7 +80,7 @@ public async Task Test() typeof(Request.Handler), new Dictionary(), new WorkerExecutionContext(WorkflowName: "test", WorkflowId: null, "", "", "", "", ""), - default + new CancellationToken(true) ); var t = sw.ElapsedMilliseconds; } From 5fda64556f4fe5ceb3ef012190f81c8afbf4ffa5 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Wed, 2 Jul 2025 16:13:54 +0200 Subject: [PATCH 15/35] Rename worker interfaces and classes --- .../Handlers/PrepareEmailHandler.cs | 2 +- .../Middlewares/CustomMiddleware.cs | 2 +- .../ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs | 2 +- .../Handlers/GetCustomerHandler.cs | 2 +- .../Handlers/PrepareEmailHandler.cs | 2 +- .../MIddlewares/PrepareEmailMiddleware.cs | 2 +- .../Extensions/IPipelineBuilder.cs | 2 +- .../Extensions/PipelineBuilder.cs | 10 +++++----- .../Interface/{INgWorker.cs => IWorker.cs} | 2 +- .../{INgWorkerMiddleware.cs => IWorkerMiddleware.cs} | 2 +- .../Middlewares/TaskExecutionTrackingMiddleware.cs | 2 +- .../Middlewares/ValidationWorkerMiddleware.cs | 2 +- .../Service/WorkerInvokerService.cs | 8 ++++---- src/ConductorSharp.Engine/Util/WorkerUtil.cs | 2 +- src/ConductorSharp.Engine/{NgWorker.cs => Worker.cs} | 2 +- src/ConductorSharp.Patterns/Tasks/CSharpLambdaTask.cs | 2 +- src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs | 2 +- src/ConductorSharp.Patterns/Tasks/WaitSeconds.cs | 2 +- .../Integration/UtilityTests.cs | 10 +++++----- .../Samples/Workers/GetCustomerHandler.cs | 2 +- .../Samples/Workers/PrepareEmailHandler.cs | 2 +- 21 files changed, 32 insertions(+), 32 deletions(-) rename src/ConductorSharp.Engine/Interface/{INgWorker.cs => IWorker.cs} (86%) rename src/ConductorSharp.Engine/Interface/{INgWorkerMiddleware.cs => IWorkerMiddleware.cs} (85%) rename src/ConductorSharp.Engine/{NgWorker.cs => Worker.cs} (75%) diff --git a/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs b/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs index 65eb413d..a480a98a 100644 --- a/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs +++ b/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs @@ -17,7 +17,7 @@ public class PrepareEmailResponse } [OriginalName("EMAIL_prepare")] -public class PrepareEmailHandler : INgWorker +public class PrepareEmailHandler : IWorker { private readonly WorkerExecutionContext _context; private readonly ILogger _logger; diff --git a/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs b/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs index e54e9166..a80e95cf 100644 --- a/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs +++ b/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs @@ -4,7 +4,7 @@ namespace ConductorSharp.Definitions.Middlewares; -internal class CustomMiddleware : INgWorkerMiddleware +internal class CustomMiddleware : IWorkerMiddleware where TRequest : class, ITaskInput, new() { private readonly ILogger> _logger; diff --git a/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs b/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs index c7a4aaa8..906293b4 100644 --- a/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs +++ b/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs @@ -16,7 +16,7 @@ public class EnumTaskOutput } [OriginalName("ENUM_task")] - public class EnumTaskHandler : INgWorker + public class EnumTaskHandler : IWorker { public Task Handle(EnumTaskInput request, WorkerExecutionContext context, CancellationToken cancellationToken) { diff --git a/examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs b/examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs index 5b44fb2b..cc43aff6 100644 --- a/examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs +++ b/examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs @@ -25,7 +25,7 @@ public class Customer } [OriginalName("CUSTOMER_get")] -public class GetCustomerHandler : INgWorker +public class GetCustomerHandler : IWorker { private static Customer[] customers = new Customer[] { diff --git a/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs b/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs index 9d3c5bdd..13f0a626 100644 --- a/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs +++ b/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs @@ -18,7 +18,7 @@ public class PrepareEmailResponse } [OriginalName("EMAIL_prepare")] - public class PrepareEmailHandler : INgWorker + public class PrepareEmailHandler : IWorker { private readonly WorkerExecutionContext _context; private readonly ILogger _logger; diff --git a/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs b/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs index b7efb10c..58a57f03 100644 --- a/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs +++ b/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs @@ -5,7 +5,7 @@ namespace ConductorSharp.NoApi.MIddlewares; -internal class PrepareEmailMiddleware : INgWorkerMiddleware +internal class PrepareEmailMiddleware : IWorkerMiddleware { private readonly ILogger _logger; diff --git a/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs index 98075fed..e4335c97 100644 --- a/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs @@ -10,7 +10,7 @@ public interface IPipelineBuilder void AddCustomMiddleware(Type middlewareType); void AddCustomMiddleware() - where TWorkerMiddleware : class, INgWorkerMiddleware + where TWorkerMiddleware : class, IWorkerMiddleware where TRequest : class, ITaskInput, new(); } } diff --git a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs index bfa1bfc8..20464305 100644 --- a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs @@ -7,15 +7,15 @@ namespace ConductorSharp.Engine.Extensions; internal class PipelineBuilder(IServiceCollection serviceCollection) : IPipelineBuilder { - public void AddValidation() => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(ValidationWorkerMiddleware<,>)); + public void AddValidation() => serviceCollection.AddTransient(typeof(IWorkerMiddleware<,>), typeof(ValidationWorkerMiddleware<,>)); public void AddExecutionTaskTracking() => - serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(TaskExecutionTrackingMiddleware<,>)); + serviceCollection.AddTransient(typeof(IWorkerMiddleware<,>), typeof(TaskExecutionTrackingMiddleware<,>)); - public void AddCustomMiddleware(Type middlewareType) => serviceCollection.AddTransient(typeof(INgWorkerMiddleware<,>), middlewareType); + public void AddCustomMiddleware(Type middlewareType) => serviceCollection.AddTransient(typeof(IWorkerMiddleware<,>), middlewareType); public void AddCustomMiddleware() - where TWorkerMiddleware : class, INgWorkerMiddleware + where TWorkerMiddleware : class, IWorkerMiddleware where TRequest : class, ITaskInput, new() => - serviceCollection.AddTransient, TWorkerMiddleware>(); + serviceCollection.AddTransient, TWorkerMiddleware>(); } diff --git a/src/ConductorSharp.Engine/Interface/INgWorker.cs b/src/ConductorSharp.Engine/Interface/IWorker.cs similarity index 86% rename from src/ConductorSharp.Engine/Interface/INgWorker.cs rename to src/ConductorSharp.Engine/Interface/IWorker.cs index 25d99fa8..3dfc6191 100644 --- a/src/ConductorSharp.Engine/Interface/INgWorker.cs +++ b/src/ConductorSharp.Engine/Interface/IWorker.cs @@ -4,7 +4,7 @@ namespace ConductorSharp.Engine.Interface; -public interface INgWorker +public interface IWorker where TRequest : class, ITaskInput, new() { Task Handle(TRequest test, WorkerExecutionContext context, CancellationToken cancellationToken); diff --git a/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs b/src/ConductorSharp.Engine/Interface/IWorkerMiddleware.cs similarity index 85% rename from src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs rename to src/ConductorSharp.Engine/Interface/IWorkerMiddleware.cs index 6e0ace81..17c82f3f 100644 --- a/src/ConductorSharp.Engine/Interface/INgWorkerMiddleware.cs +++ b/src/ConductorSharp.Engine/Interface/IWorkerMiddleware.cs @@ -5,7 +5,7 @@ namespace ConductorSharp.Engine.Interface; -public interface INgWorkerMiddleware +public interface IWorkerMiddleware where TRequest : class, ITaskInput, new() { Task Handle(TRequest request, WorkerExecutionContext context, Func> next, CancellationToken cancellationToken); diff --git a/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs index ece3ee76..43935cb3 100644 --- a/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs +++ b/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs @@ -7,7 +7,7 @@ namespace ConductorSharp.Engine.Middlewares; -public class TaskExecutionTrackingMiddleware : INgWorkerMiddleware +public class TaskExecutionTrackingMiddleware : IWorkerMiddleware where TRequest : class, ITaskInput, new() { private readonly WorkerExecutionContext _executionContext; diff --git a/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs index fb4aa14f..ba450fd0 100644 --- a/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs +++ b/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs @@ -6,7 +6,7 @@ namespace ConductorSharp.Engine.Middlewares; -public class ValidationWorkerMiddleware : INgWorkerMiddleware +public class ValidationWorkerMiddleware : IWorkerMiddleware where TRequest : class, ITaskInput, new() { public async Task Handle( diff --git a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs index 580581b0..3f26f1e3 100644 --- a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs +++ b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs @@ -25,11 +25,11 @@ public WorkerTypeInfo(Type workerType) { WorkerType = workerType; (RequestType, ResponseType) = WorkerUtil.GetRequestResponseTypes(workerType); - MiddlewareType = typeof(INgWorkerMiddleware<,>).MakeGenericType(RequestType, ResponseType); - WorkerHandleMethod = typeof(INgWorker<,>) + MiddlewareType = typeof(IWorkerMiddleware<,>).MakeGenericType(RequestType, ResponseType); + WorkerHandleMethod = typeof(IWorker<,>) .MakeGenericType(RequestType, ResponseType) - .GetMethod(nameof(INgWorker.Handle)); - MiddlewareHandleMethod = MiddlewareType.GetMethod(nameof(INgWorkerMiddleware.Handle)); + .GetMethod(nameof(IWorker.Handle)); + MiddlewareHandleMethod = MiddlewareType.GetMethod(nameof(IWorkerMiddleware.Handle)); NextFuncType = MiddlewareHandleMethod!.GetParameters().FirstOrDefault(p => p.Name == "next")!.ParameterType; TaskResultProperty = typeof(Task<>).MakeGenericType(ResponseType).GetProperty(nameof(Task.Result)); } diff --git a/src/ConductorSharp.Engine/Util/WorkerUtil.cs b/src/ConductorSharp.Engine/Util/WorkerUtil.cs index 71f85009..6e1e3f91 100644 --- a/src/ConductorSharp.Engine/Util/WorkerUtil.cs +++ b/src/ConductorSharp.Engine/Util/WorkerUtil.cs @@ -7,7 +7,7 @@ internal static class WorkerUtil { public static (Type RequestType, Type ResponseType) GetRequestResponseTypes(Type workerType) { - var types = workerType.GetInterface(typeof(INgWorker<,>).Name)!.GetGenericArguments(); + var types = workerType.GetInterface(typeof(IWorker<,>).Name)!.GetGenericArguments(); return (types[0], types[1]); } } diff --git a/src/ConductorSharp.Engine/NgWorker.cs b/src/ConductorSharp.Engine/Worker.cs similarity index 75% rename from src/ConductorSharp.Engine/NgWorker.cs rename to src/ConductorSharp.Engine/Worker.cs index 5495f3f8..9d5eef11 100644 --- a/src/ConductorSharp.Engine/NgWorker.cs +++ b/src/ConductorSharp.Engine/Worker.cs @@ -6,7 +6,7 @@ namespace ConductorSharp.Engine; -public abstract class NgWorker : SimpleTaskModel, INgWorker +public abstract class Worker : SimpleTaskModel, IWorker where TRequest : class, ITaskInput, new() { public abstract Task Handle(TRequest test, WorkerExecutionContext context, CancellationToken cancellationToken); diff --git a/src/ConductorSharp.Patterns/Tasks/CSharpLambdaTask.cs b/src/ConductorSharp.Patterns/Tasks/CSharpLambdaTask.cs index c40dcd45..979a9c36 100644 --- a/src/ConductorSharp.Patterns/Tasks/CSharpLambdaTask.cs +++ b/src/ConductorSharp.Patterns/Tasks/CSharpLambdaTask.cs @@ -30,7 +30,7 @@ internal class CSharpLambdaTaskInput : ITaskInput } [OriginalName(TaskName)] - internal class CSharpLambdaTask(WorkflowBuildItemRegistry itemRegistry) : INgWorker + internal class CSharpLambdaTask(WorkflowBuildItemRegistry itemRegistry) : IWorker { public const string TaskName = "CSHRP_inln_lmbd"; public const string LambdaTaskNameConfigurationProperty = nameof(LambdaTaskNameConfigurationProperty); diff --git a/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs b/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs index a2f80465..9da6e73b 100644 --- a/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs +++ b/src/ConductorSharp.Patterns/Tasks/ReadWorkflowTasks.cs @@ -35,7 +35,7 @@ public record WorkflowDetails(JObject InputData); /// Uses the Conductor API to read the input/output and status of the specified tasks for the specified workflow. /// [OriginalName(Constants.TaskNamePrefix + "_read_tasks")] - public class ReadWorkflowTasks(IWorkflowService workflowService) : NgWorker + public class ReadWorkflowTasks(IWorkflowService workflowService) : Worker { private readonly IWorkflowService _workflowService = workflowService; diff --git a/src/ConductorSharp.Patterns/Tasks/WaitSeconds.cs b/src/ConductorSharp.Patterns/Tasks/WaitSeconds.cs index 5c03ac6d..c93770f0 100644 --- a/src/ConductorSharp.Patterns/Tasks/WaitSeconds.cs +++ b/src/ConductorSharp.Patterns/Tasks/WaitSeconds.cs @@ -23,7 +23,7 @@ public class WaitSecondsRequest : ITaskInput /// Executes `await Task.Delay(input.Seconds * 1000)` to wait for a given amount of seconds /// [OriginalName(Constants.TaskNamePrefix + "_wait_seconds")] - public class WaitSeconds : NgWorker + public class WaitSeconds : Worker { public override async Task Handle(WaitSecondsRequest input, WorkerExecutionContext context, CancellationToken cancellationToken) { diff --git a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs index db603e2c..9a70829c 100644 --- a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs +++ b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs @@ -26,7 +26,7 @@ public class Request : ITaskInput public class Response { } - public class Handler : INgWorker + public class Handler : IWorker { public Task Handle(Request request, WorkerExecutionContext context, CancellationToken cancellationToken) { @@ -35,7 +35,7 @@ public Task Handle(Request request, WorkerExecutionContext context, Ca } } - public class Middleware : INgWorkerMiddleware + public class Middleware : IWorkerMiddleware { public async Task Handle( Request request, @@ -48,7 +48,7 @@ CancellationToken cancellationToken } } - public class GenericMiddleware : INgWorkerMiddleware + public class GenericMiddleware : IWorkerMiddleware where TRequest : class, ITaskInput, new() { public async Task Handle( @@ -67,8 +67,8 @@ public async Task Test() { var collection = new ServiceCollection(); collection.RegisterWorkerTask(); - collection.AddTransient, Middleware>(); - collection.AddTransient(typeof(INgWorkerMiddleware<,>), typeof(GenericMiddleware<,>)); + collection.AddTransient, Middleware>(); + collection.AddTransient(typeof(IWorkerMiddleware<,>), typeof(GenericMiddleware<,>)); var provider = collection.BuildServiceProvider(); var invoker = new WorkerInvokerService(provider); diff --git a/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs b/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs index c94cbe56..f8831274 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Workers/GetCustomerHandler.cs @@ -24,7 +24,7 @@ public class Customer } [OriginalName("CUSTOMER_get")] -public class GetCustomerHandler : NgWorker +public class GetCustomerHandler : Worker { public override Task Handle( GetCustomerRequest request, diff --git a/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs b/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs index 8c3e556c..a62b1bd2 100644 --- a/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs +++ b/test/ConductorSharp.Engine.Tests/Samples/Workers/PrepareEmailHandler.cs @@ -14,7 +14,7 @@ public class PrepareEmailResponse } [OriginalName("EMAIL_prepare")] -public class PrepareEmailHandler : NgWorker +public class PrepareEmailHandler : Worker { public override Task Handle( PrepareEmailRequest request, From efa3b2a5fe1d897b0864d5b9c392c5fed7dfcd24 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Wed, 2 Jul 2025 16:30:49 +0200 Subject: [PATCH 16/35] Remove unnecessary constraint --- .../ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs | 2 +- src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs | 2 +- src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs | 3 +-- src/ConductorSharp.Engine/Interface/IWorker.cs | 2 +- src/ConductorSharp.Engine/Interface/IWorkerMiddleware.cs | 2 +- .../Middlewares/TaskExecutionTrackingMiddleware.cs | 2 +- .../Middlewares/ValidationWorkerMiddleware.cs | 2 +- src/ConductorSharp.Engine/Worker.cs | 2 +- test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs | 2 +- 9 files changed, 9 insertions(+), 10 deletions(-) diff --git a/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs b/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs index a80e95cf..6294af95 100644 --- a/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs +++ b/examples/ConductorSharp.Definitions/Middlewares/CustomMiddleware.cs @@ -5,7 +5,7 @@ namespace ConductorSharp.Definitions.Middlewares; internal class CustomMiddleware : IWorkerMiddleware - where TRequest : class, ITaskInput, new() + where TRequest : ITaskInput, new() { private readonly ILogger> _logger; diff --git a/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs index e4335c97..85bb486d 100644 --- a/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/IPipelineBuilder.cs @@ -11,6 +11,6 @@ public interface IPipelineBuilder void AddCustomMiddleware() where TWorkerMiddleware : class, IWorkerMiddleware - where TRequest : class, ITaskInput, new(); + where TRequest : ITaskInput, new(); } } diff --git a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs index 20464305..8f3eeb22 100644 --- a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs @@ -16,6 +16,5 @@ public void AddExecutionTaskTracking() => public void AddCustomMiddleware() where TWorkerMiddleware : class, IWorkerMiddleware - where TRequest : class, ITaskInput, new() => - serviceCollection.AddTransient, TWorkerMiddleware>(); + where TRequest : ITaskInput, new() => serviceCollection.AddTransient, TWorkerMiddleware>(); } diff --git a/src/ConductorSharp.Engine/Interface/IWorker.cs b/src/ConductorSharp.Engine/Interface/IWorker.cs index 3dfc6191..c17c1f27 100644 --- a/src/ConductorSharp.Engine/Interface/IWorker.cs +++ b/src/ConductorSharp.Engine/Interface/IWorker.cs @@ -5,7 +5,7 @@ namespace ConductorSharp.Engine.Interface; public interface IWorker - where TRequest : class, ITaskInput, new() + where TRequest : ITaskInput, new() { Task Handle(TRequest test, WorkerExecutionContext context, CancellationToken cancellationToken); } diff --git a/src/ConductorSharp.Engine/Interface/IWorkerMiddleware.cs b/src/ConductorSharp.Engine/Interface/IWorkerMiddleware.cs index 17c82f3f..d6ae7e58 100644 --- a/src/ConductorSharp.Engine/Interface/IWorkerMiddleware.cs +++ b/src/ConductorSharp.Engine/Interface/IWorkerMiddleware.cs @@ -6,7 +6,7 @@ namespace ConductorSharp.Engine.Interface; public interface IWorkerMiddleware - where TRequest : class, ITaskInput, new() + where TRequest : ITaskInput, new() { Task Handle(TRequest request, WorkerExecutionContext context, Func> next, CancellationToken cancellationToken); } diff --git a/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs index 43935cb3..ca4fbe6b 100644 --- a/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs +++ b/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs @@ -8,7 +8,7 @@ namespace ConductorSharp.Engine.Middlewares; public class TaskExecutionTrackingMiddleware : IWorkerMiddleware - where TRequest : class, ITaskInput, new() + where TRequest : ITaskInput, new() { private readonly WorkerExecutionContext _executionContext; private readonly IEnumerable _taskExecutionServices; diff --git a/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs index ba450fd0..8c796684 100644 --- a/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs +++ b/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs @@ -7,7 +7,7 @@ namespace ConductorSharp.Engine.Middlewares; public class ValidationWorkerMiddleware : IWorkerMiddleware - where TRequest : class, ITaskInput, new() + where TRequest : ITaskInput, new() { public async Task Handle( TRequest request, diff --git a/src/ConductorSharp.Engine/Worker.cs b/src/ConductorSharp.Engine/Worker.cs index 9d5eef11..91b7d982 100644 --- a/src/ConductorSharp.Engine/Worker.cs +++ b/src/ConductorSharp.Engine/Worker.cs @@ -7,7 +7,7 @@ namespace ConductorSharp.Engine; public abstract class Worker : SimpleTaskModel, IWorker - where TRequest : class, ITaskInput, new() + where TRequest : ITaskInput, new() { public abstract Task Handle(TRequest test, WorkerExecutionContext context, CancellationToken cancellationToken); } diff --git a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs index 9a70829c..3e2df400 100644 --- a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs +++ b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs @@ -49,7 +49,7 @@ CancellationToken cancellationToken } public class GenericMiddleware : IWorkerMiddleware - where TRequest : class, ITaskInput, new() + where TRequest : ITaskInput, new() { public async Task Handle( TRequest request, From a6a4244e5bbaebe2daf3e0b6ea8e3e18a1e8f552 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Wed, 2 Jul 2025 16:34:34 +0200 Subject: [PATCH 17/35] Delete empty file --- src/ConductorSharp.Engine/Interface/IWorkerTaskLogger.cs | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/ConductorSharp.Engine/Interface/IWorkerTaskLogger.cs diff --git a/src/ConductorSharp.Engine/Interface/IWorkerTaskLogger.cs b/src/ConductorSharp.Engine/Interface/IWorkerTaskLogger.cs deleted file mode 100644 index a101ca27..00000000 --- a/src/ConductorSharp.Engine/Interface/IWorkerTaskLogger.cs +++ /dev/null @@ -1 +0,0 @@ -namespace ConductorSharp.Engine.Interface; From ff4de6ce46b180c95599e9f9a62ccb69ec72d562 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Thu, 3 Jul 2025 11:13:55 +0200 Subject: [PATCH 18/35] Fix worker --- .../ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs b/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs index 13f0a626..3acda4b4 100644 --- a/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs +++ b/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs @@ -20,12 +20,10 @@ public class PrepareEmailResponse [OriginalName("EMAIL_prepare")] public class PrepareEmailHandler : IWorker { - private readonly WorkerExecutionContext _context; private readonly ILogger _logger; - public PrepareEmailHandler(WorkerExecutionContext context, ILogger logger) + public PrepareEmailHandler(ILogger logger) { - _context = context; _logger = logger; } @@ -43,8 +41,8 @@ CancellationToken cancellationToken emailBodyBuilder.AppendLine($"Customer: {request.CustomerName}"); emailBodyBuilder.AppendLine($"Address: {request.Address}"); emailBodyBuilder.AppendLine("------------------"); - emailBodyBuilder.AppendLine($"WorkflowId : {_context.WorkflowId}"); - emailBodyBuilder.AppendLine($"WorkflowName: {_context.WorkflowName}"); + emailBodyBuilder.AppendLine($"WorkflowId : {context.WorkflowId}"); + emailBodyBuilder.AppendLine($"WorkflowName: {context.WorkflowName}"); _logger.LogInformation("Prepared email"); From d3de05e82c19ff89b4b41e156625dc1f45c2a736 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Thu, 3 Jul 2025 11:15:14 +0200 Subject: [PATCH 19/35] Fix base urls --- examples/ConductorSharp.Definitions/appsettings.json | 2 +- examples/ConductorSharp.NoApi/appsettings.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/ConductorSharp.Definitions/appsettings.json b/examples/ConductorSharp.Definitions/appsettings.json index dc040a32..87e88d20 100644 --- a/examples/ConductorSharp.Definitions/appsettings.json +++ b/examples/ConductorSharp.Definitions/appsettings.json @@ -1,6 +1,6 @@ { "Conductor": { - "BaseUrl": "http://localhost:8080", + "BaseUrl": "http://localhost:8127", "LongPollInterval": 100, "MaxConcurrentWorkers": 10, "SleepInterval": 500 diff --git a/examples/ConductorSharp.NoApi/appsettings.json b/examples/ConductorSharp.NoApi/appsettings.json index 617dd0a2..70ae1a47 100644 --- a/examples/ConductorSharp.NoApi/appsettings.json +++ b/examples/ConductorSharp.NoApi/appsettings.json @@ -1,6 +1,6 @@ { "Conductor": { - "BaseUrl": "http://localhost:48081", + "BaseUrl": "http://localhost:8127", "LongPollInterval": 100, "MaxConcurrentWorkers": 10, "SleepInterval": 2000, From 46d93887583151e0ca2eb5a571b6a3849b5d18ff Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Thu, 3 Jul 2025 11:23:57 +0200 Subject: [PATCH 20/35] Fix namespace typo --- .../ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs | 2 +- examples/ConductorSharp.NoApi/Program.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs b/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs index 58a57f03..17a5b581 100644 --- a/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs +++ b/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs @@ -3,7 +3,7 @@ using ConductorSharp.NoApi.Handlers; using Microsoft.Extensions.Logging; -namespace ConductorSharp.NoApi.MIddlewares; +namespace ConductorSharp.NoApi.Middlewares; internal class PrepareEmailMiddleware : IWorkerMiddleware { diff --git a/examples/ConductorSharp.NoApi/Program.cs b/examples/ConductorSharp.NoApi/Program.cs index 11894707..24a29588 100644 --- a/examples/ConductorSharp.NoApi/Program.cs +++ b/examples/ConductorSharp.NoApi/Program.cs @@ -2,7 +2,7 @@ using ConductorSharp.Engine.Health; using ConductorSharp.KafkaCancellationNotifier.Extensions; using ConductorSharp.NoApi.Handlers; -using ConductorSharp.NoApi.MIddlewares; +using ConductorSharp.NoApi.Middlewares; using ConductorSharp.Patterns.Extensions; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; From 347357d53e168ee1023fa0eb65cfd408e6465ea7 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Thu, 3 Jul 2025 13:17:18 +0200 Subject: [PATCH 21/35] Add initial setup for TestContainers --- ConductorSharp.sln | 6 +++ .../ConductorFixture.cs | 52 +++++++++++++++++++ ...ductorSharp.Engine.IntegrationTests.csproj | 30 +++++++++++ .../WorfklowExecutionTests.cs | 8 +++ 4 files changed, 96 insertions(+) create mode 100644 test/ConductorSharp.Engine.IntegrationTests/ConductorFixture.cs create mode 100644 test/ConductorSharp.Engine.IntegrationTests/ConductorSharp.Engine.IntegrationTests.csproj create mode 100644 test/ConductorSharp.Engine.IntegrationTests/WorfklowExecutionTests.cs diff --git a/ConductorSharp.sln b/ConductorSharp.sln index 4c182785..85767dce 100644 --- a/ConductorSharp.sln +++ b/ConductorSharp.sln @@ -30,6 +30,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConductorSharp.Patterns", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConductorSharp.KafkaCancellationNotifier", "src\ConductorSharp.KafkaCancellationNotifier\ConductorSharp.KafkaCancellationNotifier.csproj", "{A94EE48D-17F3-432A-A47D-BCB9B1EF2670}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConductorSharp.Engine.IntegrationTests", "test\ConductorSharp.Engine.IntegrationTests\ConductorSharp.Engine.IntegrationTests.csproj", "{30EACB1C-FB15-4294-AF46-3AF7ABEB2121}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -76,6 +78,10 @@ Global {A94EE48D-17F3-432A-A47D-BCB9B1EF2670}.Debug|Any CPU.Build.0 = Debug|Any CPU {A94EE48D-17F3-432A-A47D-BCB9B1EF2670}.Release|Any CPU.ActiveCfg = Release|Any CPU {A94EE48D-17F3-432A-A47D-BCB9B1EF2670}.Release|Any CPU.Build.0 = Release|Any CPU + {30EACB1C-FB15-4294-AF46-3AF7ABEB2121}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30EACB1C-FB15-4294-AF46-3AF7ABEB2121}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30EACB1C-FB15-4294-AF46-3AF7ABEB2121}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30EACB1C-FB15-4294-AF46-3AF7ABEB2121}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/test/ConductorSharp.Engine.IntegrationTests/ConductorFixture.cs b/test/ConductorSharp.Engine.IntegrationTests/ConductorFixture.cs new file mode 100644 index 00000000..a73174be --- /dev/null +++ b/test/ConductorSharp.Engine.IntegrationTests/ConductorFixture.cs @@ -0,0 +1,52 @@ +using System.Net; +using DotNet.Testcontainers.Builders; +using DotNet.Testcontainers.Containers; +using Testcontainers.PostgreSql; + +namespace ConductorSharp.Engine.IntegrationTests; + +public class ConductorFixture : IAsyncLifetime +{ + private PostgreSqlContainer _postgresContainer = null!; + private IContainer _conductorContainer = null!; + + public async Task InitializeAsync() + { + var network = new NetworkBuilder().Build(); + + _postgresContainer = new PostgreSqlBuilder() + .WithImage("postgres") + .WithUsername("conductor") + .WithPassword("conductor") + .WithNetwork(network) + .WithNetworkAliases("postgresdb") + .WithWaitStrategy( + Wait.ForUnixContainer() + .UntilMessageIsLogged("database system is ready to accept connections", w => w.WithInterval(TimeSpan.FromSeconds(5))) + ) + .Build(); + + _conductorContainer = new ContainerBuilder() + .WithImage("conductor:server") + .WithEnvironment("CONFIG_PROP", "config-postgres.properties") + .WithPortBinding(8080, true) + .WithWaitStrategy( + Wait.ForUnixContainer() + .UntilHttpRequestIsSucceeded( + r => r.ForPort(8080).ForPath("/health").ForStatusCode(HttpStatusCode.OK), + w => w.WithInterval(TimeSpan.FromSeconds(5)) + ) + ) + .WithNetwork(network) + .Build(); + + await _postgresContainer.StartAsync(); + await _conductorContainer.StartAsync(); + } + + public async Task DisposeAsync() + { + await _conductorContainer.DisposeAsync(); + await _postgresContainer.DisposeAsync(); + } +} diff --git a/test/ConductorSharp.Engine.IntegrationTests/ConductorSharp.Engine.IntegrationTests.csproj b/test/ConductorSharp.Engine.IntegrationTests/ConductorSharp.Engine.IntegrationTests.csproj new file mode 100644 index 00000000..94088d9b --- /dev/null +++ b/test/ConductorSharp.Engine.IntegrationTests/ConductorSharp.Engine.IntegrationTests.csproj @@ -0,0 +1,30 @@ + + + + net8.0 + enable + enable + + false + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/test/ConductorSharp.Engine.IntegrationTests/WorfklowExecutionTests.cs b/test/ConductorSharp.Engine.IntegrationTests/WorfklowExecutionTests.cs new file mode 100644 index 00000000..1d73f6a2 --- /dev/null +++ b/test/ConductorSharp.Engine.IntegrationTests/WorfklowExecutionTests.cs @@ -0,0 +1,8 @@ +namespace ConductorSharp.Engine.IntegrationTests +{ + public class WorfklowExecutionTests : IClassFixture + { + [Fact] + public void Test1() { } + } +} From 0099a01cb78613a3efcd596500c980d8c93bbe67 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Thu, 3 Jul 2025 16:05:42 +0200 Subject: [PATCH 22/35] Do not inject WorkerExecutionContext --- .../Handlers/PrepareEmailHandler.cs | 8 +++----- .../Extensions/ConductorSharpBuilder.cs | 2 -- .../Middlewares/TaskExecutionTrackingMiddleware.cs | 8 +++----- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs b/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs index a480a98a..4f26a883 100644 --- a/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs +++ b/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs @@ -19,12 +19,10 @@ public class PrepareEmailResponse [OriginalName("EMAIL_prepare")] public class PrepareEmailHandler : IWorker { - private readonly WorkerExecutionContext _context; private readonly ILogger _logger; - public PrepareEmailHandler(WorkerExecutionContext context, ILogger logger) + public PrepareEmailHandler(ILogger logger) { - _context = context; _logger = logger; } @@ -38,8 +36,8 @@ public async Task Handle(PrepareEmailRequest request, Work emailBodyBuilder.AppendLine($"Customer: {request.CustomerName}"); emailBodyBuilder.AppendLine($"Address: {request.Address}"); emailBodyBuilder.AppendLine("------------------"); - emailBodyBuilder.AppendLine($"WorkflowId : {_context.WorkflowId}"); - emailBodyBuilder.AppendLine($"WorkflowName: {_context.WorkflowName}"); + emailBodyBuilder.AppendLine($"WorkflowId : {context.WorkflowId}"); + emailBodyBuilder.AppendLine($"WorkflowName: {context.WorkflowName}"); _logger.LogInformation("Prepared email"); diff --git a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs index e1c8680c..4a249234 100644 --- a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs @@ -37,8 +37,6 @@ public IExecutionManagerBuilder AddExecutionManager(int maxConcurrentWorkers, in Builder.AddSingleton(); - Builder.AddScoped(); - Builder.AddSingleton(); Builder.AddTransient(); diff --git a/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs index ca4fbe6b..94d95eff 100644 --- a/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs +++ b/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs @@ -10,12 +10,10 @@ namespace ConductorSharp.Engine.Middlewares; public class TaskExecutionTrackingMiddleware : IWorkerMiddleware where TRequest : ITaskInput, new() { - private readonly WorkerExecutionContext _executionContext; private readonly IEnumerable _taskExecutionServices; - public TaskExecutionTrackingMiddleware(WorkerExecutionContext executionContext, IEnumerable taskExecutionServices) + public TaskExecutionTrackingMiddleware(IEnumerable taskExecutionServices) { - _executionContext = executionContext; _taskExecutionServices = taskExecutionServices; } @@ -28,8 +26,8 @@ CancellationToken cancellationToken { var trackedTask = new RunningTask { - TaskId = _executionContext.TaskId, - TaskName = _executionContext.TaskName, + TaskId = context.TaskId, + TaskName = context.TaskName, StartedAt = DateTimeOffset.UtcNow }; From f1e9fd9f6649ed7d4e16da8a85664eaec2bb675c Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 4 Jul 2025 00:12:50 +0200 Subject: [PATCH 23/35] Implement integration test --- .../Extensions/ServiceCollectionExtensions.cs | 4 + .../Handlers/FirstTestWorker.cs | 33 +++++++ .../Handlers/SecondTestWorker.cs | 32 +++++++ examples/ConductorSharp.ApiEnabled/Program.cs | 2 + .../Workflows/TestWorkflow.cs | 35 ++++++++ ...ductorSharp.Engine.IntegrationTests.csproj | 5 ++ .../CustomWebApplicationFactory.cs | 90 +++++++++++++++++++ .../WorfklowExecutionTests.cs | 46 +++++++++- 8 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 examples/ConductorSharp.ApiEnabled/Handlers/FirstTestWorker.cs create mode 100644 examples/ConductorSharp.ApiEnabled/Handlers/SecondTestWorker.cs create mode 100644 examples/ConductorSharp.ApiEnabled/Workflows/TestWorkflow.cs create mode 100644 test/ConductorSharp.Engine.IntegrationTests/CustomWebApplicationFactory.cs diff --git a/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs b/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs index 4648882e..f9d74c85 100644 --- a/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs +++ b/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs @@ -1,5 +1,6 @@ using ConductorSharp.ApiEnabled.Handlers; using ConductorSharp.ApiEnabled.Services; +using ConductorSharp.ApiEnabled.Workflows; using ConductorSharp.Engine.Extensions; using ConductorSharp.Engine.Health; @@ -30,6 +31,9 @@ public static IServiceCollection ConfigureApiEnabled(this IServiceCollection hos { options.OwnerEmail = "owneremail@gmail.com"; }); + hostBuilder.RegisterWorkerTask(); + hostBuilder.RegisterWorkerTask(); + hostBuilder.RegisterWorkflow(); return hostBuilder; } diff --git a/examples/ConductorSharp.ApiEnabled/Handlers/FirstTestWorker.cs b/examples/ConductorSharp.ApiEnabled/Handlers/FirstTestWorker.cs new file mode 100644 index 00000000..3ceb5de0 --- /dev/null +++ b/examples/ConductorSharp.ApiEnabled/Handlers/FirstTestWorker.cs @@ -0,0 +1,33 @@ +using ConductorSharp.Engine; +using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; + +namespace ConductorSharp.ApiEnabled.Handlers +{ + public class FirstTestWorker : ITaskInput + { + public string Input { get; set; } + + public class Response + { + public string Output { get; set; } + } + + public class Worker : Worker + { + private readonly ILogger _logger; + + public Worker(ILogger logger) + { + _logger = logger; + } + + public override Task Handle(FirstTestWorker test, WorkerExecutionContext context, CancellationToken cancellationToken) + { + _logger.LogInformation("First test worker"); + + return Task.FromResult(new() { Output = test.Input }); + } + } + } +} diff --git a/examples/ConductorSharp.ApiEnabled/Handlers/SecondTestWorker.cs b/examples/ConductorSharp.ApiEnabled/Handlers/SecondTestWorker.cs new file mode 100644 index 00000000..2aa9357f --- /dev/null +++ b/examples/ConductorSharp.ApiEnabled/Handlers/SecondTestWorker.cs @@ -0,0 +1,32 @@ +using ConductorSharp.Engine; +using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; + +namespace ConductorSharp.ApiEnabled.Handlers +{ + public class SecondTestWorker : ITaskInput + { + public string Input { get; set; } + + public class Response + { + public string Output { get; set; } + } + + public class Worker : Worker + { + private readonly ILogger _logger; + + public Worker(ILogger logger) + { + _logger = logger; + } + + public override Task Handle(SecondTestWorker test, WorkerExecutionContext context, CancellationToken cancellationToken) + { + _logger.LogInformation("Second test worker"); + return Task.FromResult(new() { Output = test.Input }); + } + } + } +} diff --git a/examples/ConductorSharp.ApiEnabled/Program.cs b/examples/ConductorSharp.ApiEnabled/Program.cs index 6c038bed..d9e4e7a4 100644 --- a/examples/ConductorSharp.ApiEnabled/Program.cs +++ b/examples/ConductorSharp.ApiEnabled/Program.cs @@ -34,3 +34,5 @@ app.MapControllers(); app.MapHealthChecks("/health"); app.Run(); + +public partial class Program { } diff --git a/examples/ConductorSharp.ApiEnabled/Workflows/TestWorkflow.cs b/examples/ConductorSharp.ApiEnabled/Workflows/TestWorkflow.cs new file mode 100644 index 00000000..e10da4e9 --- /dev/null +++ b/examples/ConductorSharp.ApiEnabled/Workflows/TestWorkflow.cs @@ -0,0 +1,35 @@ +using ConductorSharp.ApiEnabled.Handlers; +using ConductorSharp.Engine.Builders; +using ConductorSharp.Engine.Builders.Metadata; + +namespace ConductorSharp.ApiEnabled.Workflows; + +public class TestWorkflow : WorkflowInput +{ + public string Input { get; set; } + + public class Output : WorkflowOutput + { + public string Out { get; set; } + } + + [OriginalName("TEST_workflow")] + public class Workflow : Workflow + { + public Workflow(WorkflowDefinitionBuilder builder) + : base(builder) { } + + public FirstTestWorker.Worker FirstWorker { get; set; } + + public SecondTestWorker.Worker SecondWorker { get; set; } + + public override void BuildDefinition() + { + _builder.AddTask(wf => wf.FirstWorker, wf => new() { Input = wf.Input.Input }); + + _builder.AddTask(wf => wf.SecondWorker, wf => new() { Input = wf.FirstWorker.Output.Output }); + + _builder.SetOutput(wf => new() { Out = wf.SecondWorker.Output.Output }); + } + } +} diff --git a/test/ConductorSharp.Engine.IntegrationTests/ConductorSharp.Engine.IntegrationTests.csproj b/test/ConductorSharp.Engine.IntegrationTests/ConductorSharp.Engine.IntegrationTests.csproj index 94088d9b..e65ae192 100644 --- a/test/ConductorSharp.Engine.IntegrationTests/ConductorSharp.Engine.IntegrationTests.csproj +++ b/test/ConductorSharp.Engine.IntegrationTests/ConductorSharp.Engine.IntegrationTests.csproj @@ -14,6 +14,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -23,6 +24,10 @@ + + + + diff --git a/test/ConductorSharp.Engine.IntegrationTests/CustomWebApplicationFactory.cs b/test/ConductorSharp.Engine.IntegrationTests/CustomWebApplicationFactory.cs new file mode 100644 index 00000000..e76430be --- /dev/null +++ b/test/ConductorSharp.Engine.IntegrationTests/CustomWebApplicationFactory.cs @@ -0,0 +1,90 @@ +using System.Diagnostics; +using System.Net; +using ConductorSharp.ApiEnabled.Workflows; +using ConductorSharp.Client.Service; +using ConductorSharp.Engine.Util; +using DotNet.Testcontainers.Builders; +using DotNet.Testcontainers.Containers; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Testcontainers.PostgreSql; + +namespace ConductorSharp.Engine.IntegrationTests; + +public class CustomWebApplicationFactory : WebApplicationFactory, IAsyncLifetime +{ + private PostgreSqlContainer _postgresContainer = null!; + private IContainer _conductorContainer = null!; + + public async Task InitializeAsync() + { + var network = new NetworkBuilder().Build(); + + _postgresContainer = new PostgreSqlBuilder() + .WithImage("postgres") + .WithUsername("conductor") + .WithPassword("conductor") + .WithNetwork(network) + .WithNetworkAliases("postgresdb") + .WithWaitStrategy( + Wait.ForUnixContainer() + .UntilMessageIsLogged("database system is ready to accept connections", w => w.WithInterval(TimeSpan.FromSeconds(5))) + ) + .Build(); + + _conductorContainer = new ContainerBuilder() + .WithImage("conductor:server") + .WithEnvironment("CONFIG_PROP", "config-postgres.properties") + .WithPortBinding(8080, true) + .WithWaitStrategy( + Wait.ForUnixContainer() + .UntilMessageIsLogged("SystemTaskWorkerCoordinator initialized with 5 async tasks", w => w.WithInterval(TimeSpan.FromSeconds(5))) + ) + .WithNetwork(network) + .Build(); + + await _postgresContainer.StartAsync(); + await _conductorContainer.StartAsync(); + + var metadataService = Services.GetRequiredService(); + var timeout = TimeSpan.FromSeconds(10); + var deploymentStopwatch = Stopwatch.StartNew(); + var wfDeployed = false; + + while (deploymentStopwatch.Elapsed < timeout) + { + var wfs = await metadataService.ListWorkflowsAsync(); + wfDeployed = wfs.Any(wf => wf.Name == NamingUtil.NameOf()); + + if (wfDeployed) + break; + + await Task.Delay(1000); + } + + if (!wfDeployed) + throw new TimeoutException("Timeout during workflow deployment"); + } + + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + var config = new ConfigurationBuilder() + .AddInMemoryCollection( + new Dictionary() + { + { "Conductor:BaseUrl", $"http://{_conductorContainer.Hostname}:{_conductorContainer.GetMappedPublicPort(8080)}" } + }! + ) + .Build(); + + builder.UseConfiguration(config); + } + + async Task IAsyncLifetime.DisposeAsync() + { + await _conductorContainer.DisposeAsync(); + await _postgresContainer.DisposeAsync(); + } +} diff --git a/test/ConductorSharp.Engine.IntegrationTests/WorfklowExecutionTests.cs b/test/ConductorSharp.Engine.IntegrationTests/WorfklowExecutionTests.cs index 1d73f6a2..905cf7d0 100644 --- a/test/ConductorSharp.Engine.IntegrationTests/WorfklowExecutionTests.cs +++ b/test/ConductorSharp.Engine.IntegrationTests/WorfklowExecutionTests.cs @@ -1,8 +1,50 @@ +using System.Diagnostics; +using ConductorSharp.ApiEnabled.Workflows; +using ConductorSharp.Client.Generated; +using ConductorSharp.Client.Service; +using ConductorSharp.Engine.Util; +using Microsoft.Extensions.DependencyInjection; +using Task = System.Threading.Tasks.Task; + namespace ConductorSharp.Engine.IntegrationTests { - public class WorfklowExecutionTests : IClassFixture + public class WorfklowExecutionTests : IClassFixture { + private readonly CustomWebApplicationFactory _factory; + + public WorfklowExecutionTests(CustomWebApplicationFactory factory) + { + _factory = factory; + } + [Fact] - public void Test1() { } + public async Task StartWorkflowAsync() + { + var workflowService = _factory.Services.GetRequiredService(); + var workflowId = await workflowService.StartAsync(new() { Name = NamingUtil.NameOf(), Version = 1 }); + + var wf = await WaitForWorkflowTermination(workflowId); + Assert.Equal(WorkflowStatus.COMPLETED, wf.Status); + } + + private async Task WaitForWorkflowTermination(string workflowId) + { + var workflowService = _factory.Services.GetRequiredService(); + var timeout = TimeSpan.FromMinutes(5); + var sw = Stopwatch.StartNew(); + Workflow wf = null!; + + while (sw.Elapsed < timeout) + { + wf = await workflowService.GetExecutionStatusAsync(workflowId); + + if (wf.Status != WorkflowStatus.RUNNING) + break; + + await Task.Delay(1000); + } + + return wf; + } } } From c08eb3c80d7597464b24f1a7fa286992e90e01e3 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 4 Jul 2025 00:18:51 +0200 Subject: [PATCH 24/35] Change wait strategy --- .../CustomWebApplicationFactory.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/ConductorSharp.Engine.IntegrationTests/CustomWebApplicationFactory.cs b/test/ConductorSharp.Engine.IntegrationTests/CustomWebApplicationFactory.cs index e76430be..0943e58d 100644 --- a/test/ConductorSharp.Engine.IntegrationTests/CustomWebApplicationFactory.cs +++ b/test/ConductorSharp.Engine.IntegrationTests/CustomWebApplicationFactory.cs @@ -40,7 +40,10 @@ public async Task InitializeAsync() .WithPortBinding(8080, true) .WithWaitStrategy( Wait.ForUnixContainer() - .UntilMessageIsLogged("SystemTaskWorkerCoordinator initialized with 5 async tasks", w => w.WithInterval(TimeSpan.FromSeconds(5))) + .UntilHttpRequestIsSucceeded( + w => w.ForPath("/health").ForPort(8080).ForStatusCode(HttpStatusCode.OK), + w => w.WithInterval(TimeSpan.FromSeconds(5)) + ) ) .WithNetwork(network) .Build(); From de41f8d20e81e904278f3ea6fac09e3d5d229981 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 4 Jul 2025 00:21:42 +0200 Subject: [PATCH 25/35] Rename test case --- .../WorfklowExecutionTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ConductorSharp.Engine.IntegrationTests/WorfklowExecutionTests.cs b/test/ConductorSharp.Engine.IntegrationTests/WorfklowExecutionTests.cs index 905cf7d0..373cce78 100644 --- a/test/ConductorSharp.Engine.IntegrationTests/WorfklowExecutionTests.cs +++ b/test/ConductorSharp.Engine.IntegrationTests/WorfklowExecutionTests.cs @@ -18,7 +18,7 @@ public WorfklowExecutionTests(CustomWebApplicationFactory factory) } [Fact] - public async Task StartWorkflowAsync() + public async Task HostShouldExecuteWorkflowTasksSuccesfully() { var workflowService = _factory.Services.GetRequiredService(); var workflowId = await workflowService.StartAsync(new() { Name = NamingUtil.NameOf(), Version = 1 }); From 710ef953e6c7948e0a6e62c8b64a48ce24c07d83 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 4 Jul 2025 10:08:01 +0200 Subject: [PATCH 26/35] Replace IRequest with ITaskInput --- src/ConductorSharp.Engine/Interface/ITaskInput.cs | 2 +- src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs | 4 ++-- src/ConductorSharp.Toolkit/conductorsharp.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ConductorSharp.Engine/Interface/ITaskInput.cs b/src/ConductorSharp.Engine/Interface/ITaskInput.cs index 6e668049..a66e9622 100644 --- a/src/ConductorSharp.Engine/Interface/ITaskInput.cs +++ b/src/ConductorSharp.Engine/Interface/ITaskInput.cs @@ -1,3 +1,3 @@ namespace ConductorSharp.Engine.Interface; -public interface ITaskInput { } +public interface ITaskInput; diff --git a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs index 352cbae1..b623b05f 100644 --- a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs +++ b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs @@ -51,7 +51,7 @@ public string Build() CreateUsings( "ConductorSharp.Engine.Model", "ConductorSharp.Engine.Builders.Metadata", - "MediatR", + "ConductorSharp.Engine.Interface", "Newtonsoft.Json", "ConductorSharp.Engine.Builders" ) @@ -146,7 +146,7 @@ private ClassDeclarationSyntax CreateInputClass() var typeArgumentList = SyntaxFactory.TypeArgumentList( SyntaxFactory.SingletonSeparatedList(SyntaxFactory.ParseTypeName($"{ClassName}Output")) ); - var baseType = SyntaxFactory.SimpleBaseType(SyntaxFactory.GenericName("IRequest").WithTypeArgumentList(typeArgumentList)); + var baseType = SyntaxFactory.SimpleBaseType(SyntaxFactory.GenericName("ITaskInput").WithTypeArgumentList(typeArgumentList)); var baseList = SyntaxFactory.BaseList(SyntaxFactory.SingletonSeparatedList(baseType)); var classDeclaration = SyntaxFactory .ClassDeclaration($"{ClassName}Input") diff --git a/src/ConductorSharp.Toolkit/conductorsharp.yaml b/src/ConductorSharp.Toolkit/conductorsharp.yaml index 5f7580eb..b1c7005c 100644 --- a/src/ConductorSharp.Toolkit/conductorsharp.yaml +++ b/src/ConductorSharp.Toolkit/conductorsharp.yaml @@ -1,4 +1,4 @@ -baseUrl: http://localhost:8080 +baseUrl: http://localhost:8127 apiPath: api namespace: ConductorSharp.Toolkit destination: ./ConductorSharp.Toolkit/Generated \ No newline at end of file From 4280998806629b8cf3c7e53d76a67ff7ac99f2fc Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 4 Jul 2025 11:29:52 +0200 Subject: [PATCH 27/35] Add worker invoker service tests --- .../ConductorSharp.Engine.csproj | 25 +++-- .../Service/WorkerInvokerService.cs | 2 +- .../Util/EmbeddedFileHelper.cs | 102 ++++++++--------- .../Integration/UtilityTests.cs | 77 +------------ .../Unit/WorkerInvokerServiceTests.cs | 105 ++++++++++++++++++ 5 files changed, 172 insertions(+), 139 deletions(-) create mode 100644 test/ConductorSharp.Engine.Tests/Unit/WorkerInvokerServiceTests.cs diff --git a/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj b/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj index 9995d4ae..7374ae64 100644 --- a/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj +++ b/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj @@ -4,21 +4,21 @@ net6.0 preview Codaxy - Codaxy - ConductorSharp.Engine - 3.7.0 + Codaxy + ConductorSharp.Engine + 3.7.0 Client library for Netflix Conductor, with some additional quality of life features. - https://github.com/codaxy/conductor-sharp - netflix;conductor - MIT - True - False + https://github.com/codaxy/conductor-sharp + netflix;conductor + MIT + True + False - - + + @@ -26,5 +26,8 @@ - + + + + diff --git a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs index 3f26f1e3..1602fc1c 100644 --- a/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs +++ b/src/ConductorSharp.Engine/Service/WorkerInvokerService.cs @@ -17,7 +17,7 @@ namespace ConductorSharp.Engine.Service { - public class WorkerInvokerService(IServiceProvider serviceProvider) + internal class WorkerInvokerService(IServiceProvider serviceProvider) { private record WorkerTypeInfo { diff --git a/src/ConductorSharp.Engine/Util/EmbeddedFileHelper.cs b/src/ConductorSharp.Engine/Util/EmbeddedFileHelper.cs index 999573df..458aa344 100644 --- a/src/ConductorSharp.Engine/Util/EmbeddedFileHelper.cs +++ b/src/ConductorSharp.Engine/Util/EmbeddedFileHelper.cs @@ -1,51 +1,51 @@ -using System; -using System.IO; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; - -namespace ConductorSharp.Engine.Util -{ - internal static class EmbeddedFileHelper - { - private static string ReadAssemblyFile(Assembly assembly, string name) - { - var stream = assembly.GetManifestResourceStream(name) ?? throw new InvalidOperationException($"Resource {name} does not exist."); - using var reader = new StreamReader(stream, Encoding.UTF8); - - return reader.ReadToEnd(); - } - - public static T GetObjectFromEmbeddedFile(string fileName, params (string Key, object Value)[] templateParams) - { - fileName = fileName.Replace("~/", typeof(EmbeddedFileHelper).Assembly.GetName().Name + ".").Replace("/", "."); - - var contents = ReadAssemblyFile(typeof(EmbeddedFileHelper).Assembly, fileName); - - if (templateParams != null) - foreach (var (Key, Value) in templateParams) - contents = contents.Replace("{{" + Key + "}}", $"{Value}"); - - return JsonConvert.DeserializeObject(contents); - } - - public static string GetLinesFromEmbeddedFile(string fileName) - { - fileName = fileName.Replace("~/", typeof(EmbeddedFileHelper).Assembly.GetName().Name + ".").Replace("/", "."); - - var contents = ReadAssemblyFile(typeof(EmbeddedFileHelper).Assembly, fileName); - - return contents; - } - - public static Task GetObjectFromEmbeddedFileAsync(string fileName, params (string Key, object Value)[] templateParams) => - Task.FromResult(GetObjectFromEmbeddedFile(fileName, templateParams)); - - public static string Reserialize(string fileName, params (string Key, object Value)[] templateParams) - { - var file = GetObjectFromEmbeddedFile(fileName, templateParams); - return JsonConvert.SerializeObject(file); - } - } -} +//using System; +//using System.IO; +//using System.Reflection; +//using System.Text; +//using System.Threading.Tasks; +//using Newtonsoft.Json; + +//namespace ConductorSharp.Engine.Util +//{ +// internal static class EmbeddedFileHelper +// { +// private static string ReadAssemblyFile(Assembly assembly, string name) +// { +// var stream = assembly.GetManifestResourceStream(name) ?? throw new InvalidOperationException($"Resource {name} does not exist."); +// using var reader = new StreamReader(stream, Encoding.UTF8); + +// return reader.ReadToEnd(); +// } + +// public static T GetObjectFromEmbeddedFile(string fileName, params (string Key, object Value)[] templateParams) +// { +// fileName = fileName.Replace("~/", typeof(EmbeddedFileHelper).Assembly.GetName().Name + ".").Replace("/", "."); + +// var contents = ReadAssemblyFile(typeof(EmbeddedFileHelper).Assembly, fileName); + +// if (templateParams != null) +// foreach (var (Key, Value) in templateParams) +// contents = contents.Replace("{{" + Key + "}}", $"{Value}"); + +// return JsonConvert.DeserializeObject(contents); +// } + +// public static string GetLinesFromEmbeddedFile(string fileName) +// { +// fileName = fileName.Replace("~/", typeof(EmbeddedFileHelper).Assembly.GetName().Name + ".").Replace("/", "."); + +// var contents = ReadAssemblyFile(typeof(EmbeddedFileHelper).Assembly, fileName); + +// return contents; +// } + +// public static Task GetObjectFromEmbeddedFileAsync(string fileName, params (string Key, object Value)[] templateParams) => +// Task.FromResult(GetObjectFromEmbeddedFile(fileName, templateParams)); + +// public static string Reserialize(string fileName, params (string Key, object Value)[] templateParams) +// { +// var file = GetObjectFromEmbeddedFile(fileName, templateParams); +// return JsonConvert.SerializeObject(file); +// } +// } +//} diff --git a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs index 3e2df400..d9086d2a 100644 --- a/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs +++ b/test/ConductorSharp.Engine.Tests/Integration/UtilityTests.cs @@ -1,13 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ConductorSharp.Engine.Extensions; -using ConductorSharp.Engine.Service; -using ConductorSharp.Engine.Tests.Samples.Workflows; -using Microsoft.Extensions.DependencyInjection; +using ConductorSharp.Engine.Tests.Samples.Workflows; namespace ConductorSharp.Engine.Tests.Integration { @@ -19,71 +10,5 @@ public void NamingUtilShouldReturnCorrectNameableObjectName() Assert.Equal("TEST_StringInterpolation", NamingUtil.NameOf()); Assert.Equal("CUSTOMER_get", NamingUtil.NameOf()); } - - public class Request : ITaskInput - { - public string Baba { get; set; } = "Baba"; - - public class Response { } - - public class Handler : IWorker - { - public Task Handle(Request request, WorkerExecutionContext context, CancellationToken cancellationToken) - { - return Task.FromResult(new Response()); - } - } - } - - public class Middleware : IWorkerMiddleware - { - public async Task Handle( - Request request, - WorkerExecutionContext context, - Func> next, - CancellationToken cancellationToken - ) - { - return await next(); - } - } - - public class GenericMiddleware : IWorkerMiddleware - where TRequest : ITaskInput, new() - { - public async Task Handle( - TRequest request, - WorkerExecutionContext context, - Func> next, - CancellationToken cancellationToken - ) - { - return await next(); - } - } - - [Fact] - public async Task Test() - { - var collection = new ServiceCollection(); - collection.RegisterWorkerTask(); - collection.AddTransient, Middleware>(); - collection.AddTransient(typeof(IWorkerMiddleware<,>), typeof(GenericMiddleware<,>)); - - var provider = collection.BuildServiceProvider(); - var invoker = new WorkerInvokerService(provider); - - for (int i = 0; i < 5; i++) - { - var sw = Stopwatch.StartNew(); - var result = await invoker.Invoke( - typeof(Request.Handler), - new Dictionary(), - new WorkerExecutionContext(WorkflowName: "test", WorkflowId: null, "", "", "", "", ""), - new CancellationToken(true) - ); - var t = sw.ElapsedMilliseconds; - } - } } } diff --git a/test/ConductorSharp.Engine.Tests/Unit/WorkerInvokerServiceTests.cs b/test/ConductorSharp.Engine.Tests/Unit/WorkerInvokerServiceTests.cs new file mode 100644 index 00000000..c3202c97 --- /dev/null +++ b/test/ConductorSharp.Engine.Tests/Unit/WorkerInvokerServiceTests.cs @@ -0,0 +1,105 @@ +using ConductorSharp.Client; +using ConductorSharp.Engine.Extensions; +using ConductorSharp.Engine.Service; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json.Linq; + +namespace ConductorSharp.Engine.Tests.Unit; + +public class WorkerInvokerServiceTests +{ + public class Request : ITaskInput + { + public string Input { get; set; } + + public class Response + { + public string Output { get; set; } + public WorkerExecutionContext HandlerContext { get; set; } + public WorkerExecutionContext MiddlewareContext { get; set; } + public WorkerExecutionContext GenericMiddlewareContext { get; set; } + } + + public class Handler : IWorker + { + public Task Handle(Request request, WorkerExecutionContext context, CancellationToken cancellationToken) => + Task.FromResult(new Response { Output = request.Input + "Worker", HandlerContext = context }); + } + } + + public class Middleware : IWorkerMiddleware + { + public async Task Handle( + Request request, + WorkerExecutionContext context, + Func> next, + CancellationToken cancellationToken + ) + { + var response = await next(); + response.MiddlewareContext = context; + response.Output += "Middleware"; + return response; + } + } + + public class GenericMiddleware : IWorkerMiddleware + where TRequest : ITaskInput, new() + { + public async Task Handle( + TRequest request, + WorkerExecutionContext context, + Func> next, + CancellationToken cancellationToken + ) + { + var response = await next(); + var resp = (Request.Response)(object)response; + resp.GenericMiddlewareContext = context; + resp.Output += "GenericMiddleware"; + + return response; + } + } + + [Fact] + public async Task InvokerShouldInvokeWorkerAndMiddlewaresInCorrectOrder() + { + var collection = new ServiceCollection(); + collection + .AddConductorSharp(baseUrl: "http://empty/empty") + .AddExecutionManager(maxConcurrentWorkers: 1, sleepInterval: 1, longPollInterval: 1, domain: null) + .AddPipelines(pipelineBuilder => + { + pipelineBuilder.AddCustomMiddleware(); + pipelineBuilder.AddCustomMiddleware(typeof(GenericMiddleware<,>)); + }); + + collection.RegisterWorkerTask(); + + var provider = collection.BuildServiceProvider(); + + var invoker = new WorkerInvokerService(provider); + var context = new WorkerExecutionContext( + WorkflowName: "WorkflowName", + WorkflowId: "WorkflowId", + TaskName: "TaskName", + TaskId: "TaskId", + TaskReferenceName: "TaskReferenceName", + CorrelationId: "CorrelationId", + WorkerId: "WorkerId" + ); + + var result = await invoker.Invoke( + typeof(Request.Handler), + new Dictionary() { { "input", "Input" } }, + context, + new CancellationToken(true) + ); + + Assert.Equal("InputWorkerGenericMiddlewareMiddleware", result["output"]); + Assert.Equal(context, ((JObject)result["handler_context"]).ToObject(ConductorConstants.IoJsonSerializer)); + Assert.Equal(context, ((JObject)result["middleware_context"]).ToObject(ConductorConstants.IoJsonSerializer)); + Assert.Equal(context, ((JObject)result["generic_middleware_context"]).ToObject(ConductorConstants.IoJsonSerializer)); + } +} From e7bcf7b5ee6af7e27030ce0b747df9d68baf77cb Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 4 Jul 2025 11:37:00 +0200 Subject: [PATCH 28/35] Update test workflow --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 02c33541..762322c7 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -24,4 +24,4 @@ jobs: - name: Build run: dotnet build --no-restore ConductorSharp.sln - name: Test - run: dotnet test --no-restore --verbosity normal ConductorSharp.sln \ No newline at end of file + run: dotnet test --no-restore --verbosity normal test/ConductorSharp.Engine.Tests \ No newline at end of file From 927c7db946d745bfcf17b37b7648a9f9011cbaad Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 4 Jul 2025 11:44:58 +0200 Subject: [PATCH 29/35] Add arg check --- src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs index 8f3eeb22..93e6a0f1 100644 --- a/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs +++ b/src/ConductorSharp.Engine/Extensions/PipelineBuilder.cs @@ -12,7 +12,13 @@ internal class PipelineBuilder(IServiceCollection serviceCollection) : IPipeline public void AddExecutionTaskTracking() => serviceCollection.AddTransient(typeof(IWorkerMiddleware<,>), typeof(TaskExecutionTrackingMiddleware<,>)); - public void AddCustomMiddleware(Type middlewareType) => serviceCollection.AddTransient(typeof(IWorkerMiddleware<,>), middlewareType); + public void AddCustomMiddleware(Type middlewareType) + { + if (middlewareType.GetInterface(typeof(IWorkerMiddleware<,>).Name) is null) + throw new ArgumentException($"Generic middleware must implement interface {typeof(IWorkerMiddleware<,>).Name}", nameof(middlewareType)); + + serviceCollection.AddTransient(typeof(IWorkerMiddleware<,>), middlewareType); + } public void AddCustomMiddleware() where TWorkerMiddleware : class, IWorkerMiddleware From afea316231a3c123c4704f6f01e9bb8cebc8ef7a Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 4 Jul 2025 12:24:15 +0200 Subject: [PATCH 30/35] Rename handlers to workers --- .../Extensions/ServiceCollectionExtensions.cs | 7 ++-- .../Handlers/SecondTestWorker.cs | 32 ------------------- .../{Handlers => Workers}/FirstTestWorker.cs | 2 +- .../PrepareEmailWorker.cs} | 8 ++--- .../Workers/SecondTestWorker.cs | 31 ++++++++++++++++++ .../Workflows/TestWorkflow.cs | 3 +- .../Handlers/EnumTaskHandler.cs | 27 ---------------- .../MIddlewares/PrepareEmailMiddleware.cs | 6 ++-- examples/ConductorSharp.NoApi/Program.cs | 9 +++--- .../Workers/EnumTaskWorker.cs | 26 +++++++++++++++ .../GetCustomerWorker.cs} | 4 +-- .../PrepareEmailWorker.cs} | 8 ++--- 12 files changed, 81 insertions(+), 82 deletions(-) delete mode 100644 examples/ConductorSharp.ApiEnabled/Handlers/SecondTestWorker.cs rename examples/ConductorSharp.ApiEnabled/{Handlers => Workers}/FirstTestWorker.cs (95%) rename examples/ConductorSharp.ApiEnabled/{Handlers/PrepareEmailHandler.cs => Workers/PrepareEmailWorker.cs} (84%) create mode 100644 examples/ConductorSharp.ApiEnabled/Workers/SecondTestWorker.cs delete mode 100644 examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs create mode 100644 examples/ConductorSharp.NoApi/Workers/EnumTaskWorker.cs rename examples/ConductorSharp.NoApi/{Handlers/GetCustomerHandler.cs => Workers/GetCustomerWorker.cs} (90%) rename examples/ConductorSharp.NoApi/{Handlers/PrepareEmailHandler.cs => Workers/PrepareEmailWorker.cs} (86%) diff --git a/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs b/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs index f9d74c85..fff284f2 100644 --- a/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs +++ b/examples/ConductorSharp.ApiEnabled/Extensions/ServiceCollectionExtensions.cs @@ -1,5 +1,6 @@ -using ConductorSharp.ApiEnabled.Handlers; -using ConductorSharp.ApiEnabled.Services; +using ConductorSharp.ApiEnabled.Services; +using ConductorSharp.ApiEnabled.Workers; +using ConductorSharp.ApiEnabled.Workers; using ConductorSharp.ApiEnabled.Workflows; using ConductorSharp.Engine.Extensions; using ConductorSharp.Engine.Health; @@ -27,7 +28,7 @@ public static IServiceCollection ConfigureApiEnabled(this IServiceCollection hos }); hostBuilder.AddSingleton(); - hostBuilder.RegisterWorkerTask(options => + hostBuilder.RegisterWorkerTask(options => { options.OwnerEmail = "owneremail@gmail.com"; }); diff --git a/examples/ConductorSharp.ApiEnabled/Handlers/SecondTestWorker.cs b/examples/ConductorSharp.ApiEnabled/Handlers/SecondTestWorker.cs deleted file mode 100644 index 2aa9357f..00000000 --- a/examples/ConductorSharp.ApiEnabled/Handlers/SecondTestWorker.cs +++ /dev/null @@ -1,32 +0,0 @@ -using ConductorSharp.Engine; -using ConductorSharp.Engine.Interface; -using ConductorSharp.Engine.Util; - -namespace ConductorSharp.ApiEnabled.Handlers -{ - public class SecondTestWorker : ITaskInput - { - public string Input { get; set; } - - public class Response - { - public string Output { get; set; } - } - - public class Worker : Worker - { - private readonly ILogger _logger; - - public Worker(ILogger logger) - { - _logger = logger; - } - - public override Task Handle(SecondTestWorker test, WorkerExecutionContext context, CancellationToken cancellationToken) - { - _logger.LogInformation("Second test worker"); - return Task.FromResult(new() { Output = test.Input }); - } - } - } -} diff --git a/examples/ConductorSharp.ApiEnabled/Handlers/FirstTestWorker.cs b/examples/ConductorSharp.ApiEnabled/Workers/FirstTestWorker.cs similarity index 95% rename from examples/ConductorSharp.ApiEnabled/Handlers/FirstTestWorker.cs rename to examples/ConductorSharp.ApiEnabled/Workers/FirstTestWorker.cs index 3ceb5de0..c6c2984e 100644 --- a/examples/ConductorSharp.ApiEnabled/Handlers/FirstTestWorker.cs +++ b/examples/ConductorSharp.ApiEnabled/Workers/FirstTestWorker.cs @@ -2,7 +2,7 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Util; -namespace ConductorSharp.ApiEnabled.Handlers +namespace ConductorSharp.ApiEnabled.Workers { public class FirstTestWorker : ITaskInput { diff --git a/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs b/examples/ConductorSharp.ApiEnabled/Workers/PrepareEmailWorker.cs similarity index 84% rename from examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs rename to examples/ConductorSharp.ApiEnabled/Workers/PrepareEmailWorker.cs index 4f26a883..41e0e936 100644 --- a/examples/ConductorSharp.ApiEnabled/Handlers/PrepareEmailHandler.cs +++ b/examples/ConductorSharp.ApiEnabled/Workers/PrepareEmailWorker.cs @@ -3,7 +3,7 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Util; -namespace ConductorSharp.ApiEnabled.Handlers; +namespace ConductorSharp.ApiEnabled.Workers; public class PrepareEmailRequest : ITaskInput { @@ -17,11 +17,11 @@ public class PrepareEmailResponse } [OriginalName("EMAIL_prepare")] -public class PrepareEmailHandler : IWorker +public class PrepareEmailWorker : IWorker { - private readonly ILogger _logger; + private readonly ILogger _logger; - public PrepareEmailHandler(ILogger logger) + public PrepareEmailWorker(ILogger logger) { _logger = logger; } diff --git a/examples/ConductorSharp.ApiEnabled/Workers/SecondTestWorker.cs b/examples/ConductorSharp.ApiEnabled/Workers/SecondTestWorker.cs new file mode 100644 index 00000000..c9dcbd5b --- /dev/null +++ b/examples/ConductorSharp.ApiEnabled/Workers/SecondTestWorker.cs @@ -0,0 +1,31 @@ +using ConductorSharp.Engine; +using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; + +namespace ConductorSharp.ApiEnabled.Workers; + +public class SecondTestWorker : ITaskInput +{ + public string Input { get; set; } + + public class Response + { + public string Output { get; set; } + } + + public class Worker : Worker + { + private readonly ILogger _logger; + + public Worker(ILogger logger) + { + _logger = logger; + } + + public override Task Handle(SecondTestWorker test, WorkerExecutionContext context, CancellationToken cancellationToken) + { + _logger.LogInformation("Second test worker"); + return Task.FromResult(new() { Output = test.Input }); + } + } +} diff --git a/examples/ConductorSharp.ApiEnabled/Workflows/TestWorkflow.cs b/examples/ConductorSharp.ApiEnabled/Workflows/TestWorkflow.cs index e10da4e9..a728c1d6 100644 --- a/examples/ConductorSharp.ApiEnabled/Workflows/TestWorkflow.cs +++ b/examples/ConductorSharp.ApiEnabled/Workflows/TestWorkflow.cs @@ -1,4 +1,5 @@ -using ConductorSharp.ApiEnabled.Handlers; +using ConductorSharp.ApiEnabled.Workers; +using ConductorSharp.ApiEnabled.Workers; using ConductorSharp.Engine.Builders; using ConductorSharp.Engine.Builders.Metadata; diff --git a/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs b/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs deleted file mode 100644 index 906293b4..00000000 --- a/examples/ConductorSharp.NoApi/Handlers/EnumTaskHandler.cs +++ /dev/null @@ -1,27 +0,0 @@ -using ConductorSharp.Client.Generated; -using ConductorSharp.Engine.Builders.Metadata; -using ConductorSharp.Engine.Interface; -using ConductorSharp.Engine.Util; - -namespace ConductorSharp.NoApi.Handlers -{ - public class EnumTaskInput : ITaskInput - { - public WorkflowStatus Status { get; set; } - } - - public class EnumTaskOutput - { - public WorkflowStatus Status { get; set; } - } - - [OriginalName("ENUM_task")] - public class EnumTaskHandler : IWorker - { - public Task Handle(EnumTaskInput request, WorkerExecutionContext context, CancellationToken cancellationToken) - { - Console.WriteLine(request.Status); - return System.Threading.Tasks.Task.FromResult(new EnumTaskOutput() { Status = request.Status }); - } - } -} diff --git a/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs b/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs index 17a5b581..025a582e 100644 --- a/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs +++ b/examples/ConductorSharp.NoApi/MIddlewares/PrepareEmailMiddleware.cs @@ -1,6 +1,6 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Util; -using ConductorSharp.NoApi.Handlers; +using ConductorSharp.NoApi.Workers; using Microsoft.Extensions.Logging; namespace ConductorSharp.NoApi.Middlewares; @@ -21,9 +21,9 @@ public async Task Handle( CancellationToken cancellationToken ) { - _logger.LogInformation($"Executed only before {nameof(PrepareEmailHandler)}"); + _logger.LogInformation($"Executed only before {nameof(PrepareEmailWorker)}"); var response = await next(); - _logger.LogInformation($"Executed only after {nameof(PrepareEmailHandler)}"); + _logger.LogInformation($"Executed only after {nameof(PrepareEmailWorker)}"); return response; } } diff --git a/examples/ConductorSharp.NoApi/Program.cs b/examples/ConductorSharp.NoApi/Program.cs index 24a29588..ed406a95 100644 --- a/examples/ConductorSharp.NoApi/Program.cs +++ b/examples/ConductorSharp.NoApi/Program.cs @@ -1,8 +1,7 @@ using ConductorSharp.Engine.Extensions; using ConductorSharp.Engine.Health; -using ConductorSharp.KafkaCancellationNotifier.Extensions; -using ConductorSharp.NoApi.Handlers; using ConductorSharp.NoApi.Middlewares; +using ConductorSharp.NoApi.Workers; using ConductorSharp.Patterns.Extensions; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -43,9 +42,9 @@ // topicName: configuration.GetValue("Conductor:KafkaCancellationNotifier:TopicName"), // groupId: configuration.GetValue("Conductor:KafkaCancellationNotifier:GroupId")); - services.RegisterWorkerTask(); - services.RegisterWorkerTask(); - services.RegisterWorkerTask(); + services.RegisterWorkerTask(); + services.RegisterWorkerTask(); + services.RegisterWorkerTask(); } ); diff --git a/examples/ConductorSharp.NoApi/Workers/EnumTaskWorker.cs b/examples/ConductorSharp.NoApi/Workers/EnumTaskWorker.cs new file mode 100644 index 00000000..893d07c0 --- /dev/null +++ b/examples/ConductorSharp.NoApi/Workers/EnumTaskWorker.cs @@ -0,0 +1,26 @@ +using ConductorSharp.Client.Generated; +using ConductorSharp.Engine.Builders.Metadata; +using ConductorSharp.Engine.Interface; +using ConductorSharp.Engine.Util; + +namespace ConductorSharp.NoApi.Workers; + +public class EnumTaskInput : ITaskInput +{ + public WorkflowStatus Status { get; set; } +} + +public class EnumTaskOutput +{ + public WorkflowStatus Status { get; set; } +} + +[OriginalName("ENUM_task")] +public class EnumTaskWorker : IWorker +{ + public Task Handle(EnumTaskInput request, WorkerExecutionContext context, CancellationToken cancellationToken) + { + Console.WriteLine(request.Status); + return System.Threading.Tasks.Task.FromResult(new EnumTaskOutput() { Status = request.Status }); + } +} diff --git a/examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs b/examples/ConductorSharp.NoApi/Workers/GetCustomerWorker.cs similarity index 90% rename from examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs rename to examples/ConductorSharp.NoApi/Workers/GetCustomerWorker.cs index cc43aff6..b86bc9b7 100644 --- a/examples/ConductorSharp.NoApi/Handlers/GetCustomerHandler.cs +++ b/examples/ConductorSharp.NoApi/Workers/GetCustomerWorker.cs @@ -3,7 +3,7 @@ using ConductorSharp.Engine.Interface; using ConductorSharp.Engine.Util; -namespace ConductorSharp.NoApi.Handlers; +namespace ConductorSharp.NoApi.Workers; public class GetCustomerRequest : ITaskInput { @@ -25,7 +25,7 @@ public class Customer } [OriginalName("CUSTOMER_get")] -public class GetCustomerHandler : IWorker +public class GetCustomerWorker : IWorker { private static Customer[] customers = new Customer[] { diff --git a/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs b/examples/ConductorSharp.NoApi/Workers/PrepareEmailWorker.cs similarity index 86% rename from examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs rename to examples/ConductorSharp.NoApi/Workers/PrepareEmailWorker.cs index 3acda4b4..9b3b0ada 100644 --- a/examples/ConductorSharp.NoApi/Handlers/PrepareEmailHandler.cs +++ b/examples/ConductorSharp.NoApi/Workers/PrepareEmailWorker.cs @@ -4,7 +4,7 @@ using ConductorSharp.Engine.Util; using Microsoft.Extensions.Logging; -namespace ConductorSharp.NoApi.Handlers +namespace ConductorSharp.NoApi.Workers { public class PrepareEmailRequest : ITaskInput { @@ -18,11 +18,11 @@ public class PrepareEmailResponse } [OriginalName("EMAIL_prepare")] - public class PrepareEmailHandler : IWorker + public class PrepareEmailWorker : IWorker { - private readonly ILogger _logger; + private readonly ILogger _logger; - public PrepareEmailHandler(ILogger logger) + public PrepareEmailWorker(ILogger logger) { _logger = logger; } From 254254df7bcb385ac02f07602f9317cf43211724 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 4 Jul 2025 12:39:31 +0200 Subject: [PATCH 31/35] Remove unused fixture --- .../ConductorFixture.cs | 52 ------------------- 1 file changed, 52 deletions(-) delete mode 100644 test/ConductorSharp.Engine.IntegrationTests/ConductorFixture.cs diff --git a/test/ConductorSharp.Engine.IntegrationTests/ConductorFixture.cs b/test/ConductorSharp.Engine.IntegrationTests/ConductorFixture.cs deleted file mode 100644 index a73174be..00000000 --- a/test/ConductorSharp.Engine.IntegrationTests/ConductorFixture.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Net; -using DotNet.Testcontainers.Builders; -using DotNet.Testcontainers.Containers; -using Testcontainers.PostgreSql; - -namespace ConductorSharp.Engine.IntegrationTests; - -public class ConductorFixture : IAsyncLifetime -{ - private PostgreSqlContainer _postgresContainer = null!; - private IContainer _conductorContainer = null!; - - public async Task InitializeAsync() - { - var network = new NetworkBuilder().Build(); - - _postgresContainer = new PostgreSqlBuilder() - .WithImage("postgres") - .WithUsername("conductor") - .WithPassword("conductor") - .WithNetwork(network) - .WithNetworkAliases("postgresdb") - .WithWaitStrategy( - Wait.ForUnixContainer() - .UntilMessageIsLogged("database system is ready to accept connections", w => w.WithInterval(TimeSpan.FromSeconds(5))) - ) - .Build(); - - _conductorContainer = new ContainerBuilder() - .WithImage("conductor:server") - .WithEnvironment("CONFIG_PROP", "config-postgres.properties") - .WithPortBinding(8080, true) - .WithWaitStrategy( - Wait.ForUnixContainer() - .UntilHttpRequestIsSucceeded( - r => r.ForPort(8080).ForPath("/health").ForStatusCode(HttpStatusCode.OK), - w => w.WithInterval(TimeSpan.FromSeconds(5)) - ) - ) - .WithNetwork(network) - .Build(); - - await _postgresContainer.StartAsync(); - await _conductorContainer.StartAsync(); - } - - public async Task DisposeAsync() - { - await _conductorContainer.DisposeAsync(); - await _postgresContainer.DisposeAsync(); - } -} From ba548fe5f1bc5e8e9c6a5157425f2aeeb8437a6b Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 4 Jul 2025 12:40:21 +0200 Subject: [PATCH 32/35] Remove unused class --- .../Util/EmbeddedFileHelper.cs | 51 ------------------- 1 file changed, 51 deletions(-) delete mode 100644 src/ConductorSharp.Engine/Util/EmbeddedFileHelper.cs diff --git a/src/ConductorSharp.Engine/Util/EmbeddedFileHelper.cs b/src/ConductorSharp.Engine/Util/EmbeddedFileHelper.cs deleted file mode 100644 index 458aa344..00000000 --- a/src/ConductorSharp.Engine/Util/EmbeddedFileHelper.cs +++ /dev/null @@ -1,51 +0,0 @@ -//using System; -//using System.IO; -//using System.Reflection; -//using System.Text; -//using System.Threading.Tasks; -//using Newtonsoft.Json; - -//namespace ConductorSharp.Engine.Util -//{ -// internal static class EmbeddedFileHelper -// { -// private static string ReadAssemblyFile(Assembly assembly, string name) -// { -// var stream = assembly.GetManifestResourceStream(name) ?? throw new InvalidOperationException($"Resource {name} does not exist."); -// using var reader = new StreamReader(stream, Encoding.UTF8); - -// return reader.ReadToEnd(); -// } - -// public static T GetObjectFromEmbeddedFile(string fileName, params (string Key, object Value)[] templateParams) -// { -// fileName = fileName.Replace("~/", typeof(EmbeddedFileHelper).Assembly.GetName().Name + ".").Replace("/", "."); - -// var contents = ReadAssemblyFile(typeof(EmbeddedFileHelper).Assembly, fileName); - -// if (templateParams != null) -// foreach (var (Key, Value) in templateParams) -// contents = contents.Replace("{{" + Key + "}}", $"{Value}"); - -// return JsonConvert.DeserializeObject(contents); -// } - -// public static string GetLinesFromEmbeddedFile(string fileName) -// { -// fileName = fileName.Replace("~/", typeof(EmbeddedFileHelper).Assembly.GetName().Name + ".").Replace("/", "."); - -// var contents = ReadAssemblyFile(typeof(EmbeddedFileHelper).Assembly, fileName); - -// return contents; -// } - -// public static Task GetObjectFromEmbeddedFileAsync(string fileName, params (string Key, object Value)[] templateParams) => -// Task.FromResult(GetObjectFromEmbeddedFile(fileName, templateParams)); - -// public static string Reserialize(string fileName, params (string Key, object Value)[] templateParams) -// { -// var file = GetObjectFromEmbeddedFile(fileName, templateParams); -// return JsonConvert.SerializeObject(file); -// } -// } -//} From 3879e30faabbb2709363fe56d7ac86a5f64eb4a8 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 4 Jul 2025 14:23:46 +0200 Subject: [PATCH 33/35] Make classes internal --- .../Middlewares/TaskExecutionTrackingMiddleware.cs | 2 +- .../Middlewares/ValidationWorkerMiddleware.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs index 94d95eff..d6b42614 100644 --- a/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs +++ b/src/ConductorSharp.Engine/Middlewares/TaskExecutionTrackingMiddleware.cs @@ -7,7 +7,7 @@ namespace ConductorSharp.Engine.Middlewares; -public class TaskExecutionTrackingMiddleware : IWorkerMiddleware +internal class TaskExecutionTrackingMiddleware : IWorkerMiddleware where TRequest : ITaskInput, new() { private readonly IEnumerable _taskExecutionServices; diff --git a/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs b/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs index 8c796684..94759fd0 100644 --- a/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs +++ b/src/ConductorSharp.Engine/Middlewares/ValidationWorkerMiddleware.cs @@ -6,7 +6,7 @@ namespace ConductorSharp.Engine.Middlewares; -public class ValidationWorkerMiddleware : IWorkerMiddleware +internal class ValidationWorkerMiddleware : IWorkerMiddleware where TRequest : ITaskInput, new() { public async Task Handle( From 4be36bfacd57be91bc3fa0f55e7dac108511b534 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 4 Jul 2025 14:53:27 +0200 Subject: [PATCH 34/35] Copy context --- .../Unit/WorkerInvokerServiceTests.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/ConductorSharp.Engine.Tests/Unit/WorkerInvokerServiceTests.cs b/test/ConductorSharp.Engine.Tests/Unit/WorkerInvokerServiceTests.cs index c3202c97..f3645b73 100644 --- a/test/ConductorSharp.Engine.Tests/Unit/WorkerInvokerServiceTests.cs +++ b/test/ConductorSharp.Engine.Tests/Unit/WorkerInvokerServiceTests.cs @@ -90,6 +90,7 @@ public async Task InvokerShouldInvokeWorkerAndMiddlewaresInCorrectOrder() WorkerId: "WorkerId" ); + var expectedContext = context with { }; var result = await invoker.Invoke( typeof(Request.Handler), new Dictionary() { { "input", "Input" } }, @@ -98,8 +99,11 @@ public async Task InvokerShouldInvokeWorkerAndMiddlewaresInCorrectOrder() ); Assert.Equal("InputWorkerGenericMiddlewareMiddleware", result["output"]); - Assert.Equal(context, ((JObject)result["handler_context"]).ToObject(ConductorConstants.IoJsonSerializer)); - Assert.Equal(context, ((JObject)result["middleware_context"]).ToObject(ConductorConstants.IoJsonSerializer)); - Assert.Equal(context, ((JObject)result["generic_middleware_context"]).ToObject(ConductorConstants.IoJsonSerializer)); + Assert.Equal(expectedContext, ((JObject)result["handler_context"]).ToObject(ConductorConstants.IoJsonSerializer)); + Assert.Equal(expectedContext, ((JObject)result["middleware_context"]).ToObject(ConductorConstants.IoJsonSerializer)); + Assert.Equal( + expectedContext, + ((JObject)result["generic_middleware_context"]).ToObject(ConductorConstants.IoJsonSerializer) + ); } } From 3ebe79ec3141558732e5a39ab43ff429a0282ca8 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 4 Jul 2025 15:11:33 +0200 Subject: [PATCH 35/35] Delete unused embedded files --- .../ConductorSharp.Toolkit.csproj | 14 --------- .../Templates/TaskCollectionTemplate.default | 20 ------------ .../Templates/WorkerTemplate.default | 31 ------------------- .../WorkflowCollectionTemplate.default | 21 ------------- .../Templates/WorkflowTemplate.default | 30 ------------------ 5 files changed, 116 deletions(-) delete mode 100644 src/ConductorSharp.Toolkit/Templates/TaskCollectionTemplate.default delete mode 100644 src/ConductorSharp.Toolkit/Templates/WorkerTemplate.default delete mode 100644 src/ConductorSharp.Toolkit/Templates/WorkflowCollectionTemplate.default delete mode 100644 src/ConductorSharp.Toolkit/Templates/WorkflowTemplate.default diff --git a/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj b/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj index b103e438..b9a49088 100644 --- a/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj +++ b/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj @@ -10,20 +10,6 @@ 3.0.1-beta3 - - - - - - - - - - - - - - diff --git a/src/ConductorSharp.Toolkit/Templates/TaskCollectionTemplate.default b/src/ConductorSharp.Toolkit/Templates/TaskCollectionTemplate.default deleted file mode 100644 index 38ae9b09..00000000 --- a/src/ConductorSharp.Toolkit/Templates/TaskCollectionTemplate.default +++ /dev/null @@ -1,20 +0,0 @@ -using ConductorSharp.Engine.Model; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using Newtonsoft.Json; -using MediatR; -using ConductorSharp.Engine.Util; - -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace {{namespace}} -{ - {{taskCollection}} -} diff --git a/src/ConductorSharp.Toolkit/Templates/WorkerTemplate.default b/src/ConductorSharp.Toolkit/Templates/WorkerTemplate.default deleted file mode 100644 index bd834386..00000000 --- a/src/ConductorSharp.Toolkit/Templates/WorkerTemplate.default +++ /dev/null @@ -1,31 +0,0 @@ - public partial class {{workerName}}Input : IRequest<{{workerName}}Output> - { -{{inputProperties}} - } - - public partial class {{workerName}}Output - { -{{outputProperties}} - } - - /// - /// {{commentDescription}} - /// - /// - /// {{originalName}} - /// - /// - /// {{ownerEmail}} - /// - /// - /// {{ownerApp}} - /// - /// - /// {{note}} - /// - [OriginalName("{{originalName}}")] - public partial class {{workerName}} : SimpleTaskModel<{{workerName}}Input, {{workerName}}Output> - { - } - - diff --git a/src/ConductorSharp.Toolkit/Templates/WorkflowCollectionTemplate.default b/src/ConductorSharp.Toolkit/Templates/WorkflowCollectionTemplate.default deleted file mode 100644 index 98daf1a7..00000000 --- a/src/ConductorSharp.Toolkit/Templates/WorkflowCollectionTemplate.default +++ /dev/null @@ -1,21 +0,0 @@ -using ConductorSharp.Engine.Model; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using Newtonsoft.Json; -using ConductorSharp.Engine.Builders; -using MediatR; -using ConductorSharp.Engine.Util; - -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace {{namespace}} -{ - {{workflowCollection}} -} diff --git a/src/ConductorSharp.Toolkit/Templates/WorkflowTemplate.default b/src/ConductorSharp.Toolkit/Templates/WorkflowTemplate.default deleted file mode 100644 index 684cccd7..00000000 --- a/src/ConductorSharp.Toolkit/Templates/WorkflowTemplate.default +++ /dev/null @@ -1,30 +0,0 @@ - public partial class {{workflowName}}Input : IRequest<{{workflowName}}Output> - { -{{inputProperties}} - } - - public partial class {{workflowName}}Output - { - } - - /// - /// {{commentDescription}} - /// - /// - /// {{originalName}} - /// - /// - /// {{ownerEmail}} - /// - /// - /// {{ownerApp}} - /// - /// - /// {{note}} - /// - [OriginalName("{{originalName}}")] - public partial class {{workflowName}} : SubWorkflowTaskModel<{{workflowName}}Input, {{workflowName}}Output> - { - } - -