Add OpenTelemetry module (#5810)
* Add OpenTelemetry integration for workflow tracing Introduced a new module, Elsa.OpenTelemetry, to provide OpenTelemetry sources for tracing workflow and activity execution. Updated various components and pipeline extensions to support OpenTelemetry tracing throughout the workflow execution process. * Refactor workflow execution pipelines Deleted `WorkflowsFeatureExtensions` and migrated methods to `PipelineWorkflowsFeatureExtensions` with added configurability. Enhanced `ActivityExecutionMiddlewareExtensions` and `ActivityExecutionPipelinePipelineBuilder` to support middleware insertion. Added comprehensive tracing to `OpenTelemetryTracingWorkflowExecutionMiddleware`. * Add OpenTelemetry tracing to activity execution Introduced `OpenTelemetryTracingActivityExecutionMiddleware` to capture tracing information for activity execution within workflows. This middleware logs activity execution start and end events, attaching pertinent activity tags. Added extension method to register this middleware in the workflow execution pipeline. * Set `PYTHONNET_PYDLL` consistently and update workflow pipelines Update Dockerfiles to set the `PYTHONNET_PYDLL` environment variable consistently without spaces. Additionally, refactor `Program.cs` to streamline workflow and activity execution pipeline configurations by using the `WithDefaultWorkflowExecutionPipeline` and `WithDefaultActivityExecutionPipeline` methods. * Enhance OpenTelemetry Tracing Middleware Implementation Add missing activity tags and events to improve telemetry data. Simplify middleware installation syntax for both workflow and activity execution tracing pipelines, ensuring consistent and clear tracing across modules.
This commit is contained in:
parent
b4cd4dd465
commit
70b8582b23
7
Elsa.sln
7
Elsa.sln
|
|
@ -373,6 +373,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.ServerAndStudio.Web",
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Studio.Web", "src\apps\Elsa.Studio.Web\Elsa.Studio.Web.csproj", "{169A82A5-2DB3-40EA-801E-14C08D743DF7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.OpenTelemetry", "src\modules\Elsa.OpenTelemetry\Elsa.OpenTelemetry.csproj", "{2CDF3E1C-267D-4198-B1C7-7E1F548FC120}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -885,6 +887,10 @@ Global
|
|||
{169A82A5-2DB3-40EA-801E-14C08D743DF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{169A82A5-2DB3-40EA-801E-14C08D743DF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{169A82A5-2DB3-40EA-801E-14C08D743DF7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2CDF3E1C-267D-4198-B1C7-7E1F548FC120}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2CDF3E1C-267D-4198-B1C7-7E1F548FC120}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2CDF3E1C-267D-4198-B1C7-7E1F548FC120}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2CDF3E1C-267D-4198-B1C7-7E1F548FC120}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -1039,6 +1045,7 @@ Global
|
|||
{690B0274-291F-4D9E-BA76-54EFF7D3E4BC} = {D92BEAB2-60D6-4BB4-885A-6BA681C6CCF1}
|
||||
{060FD0BA-BD78-48E1-A8A7-4906A5AD5E39} = {D92BEAB2-60D6-4BB4-885A-6BA681C6CCF1}
|
||||
{169A82A5-2DB3-40EA-801E-14C08D743DF7} = {D92BEAB2-60D6-4BB4-885A-6BA681C6CCF1}
|
||||
{2CDF3E1C-267D-4198-B1C7-7E1F548FC120} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {D4B5CEAA-7D70-4FCB-A68E-B03FBE5E0E5E}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Set PYTHONNET_PYDLL environment variable
|
||||
ENV PYTHONNET_PYDLL /usr/lib/aarch64-linux-gnu/libpython3.11.so
|
||||
ENV PYTHONNET_PYDLL=/usr/lib/aarch64-linux-gnu/libpython3.11.so
|
||||
|
||||
# Copy the tracer from build target
|
||||
COPY --from=build /tmp/datadog-dotnet-apm.deb /tmp/datadog-dotnet-apm.deb
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Set PYTHONNET_PYDLL environment variable
|
||||
ENV PYTHONNET_PYDLL /usr/lib/aarch64-linux-gnu/libpython3.11.so
|
||||
ENV PYTHONNET_PYDLL=/usr/lib/aarch64-linux-gnu/libpython3.11.so
|
||||
|
||||
EXPOSE 80/tcp
|
||||
EXPOSE 443/tcp
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Set PYTHONNET_PYDLL environment variable
|
||||
ENV PYTHONNET_PYDLL /usr/lib/aarch64-linux-gnu/libpython3.11.so
|
||||
ENV PYTHONNET_PYDLL=/usr/lib/aarch64-linux-gnu/libpython3.11.so
|
||||
|
||||
EXPOSE 80/tcp
|
||||
EXPOSE 443/tcp
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
<ProjectReference Include="..\..\modules\Elsa.Caching.Distributed.MassTransit\Elsa.Caching.Distributed.MassTransit.csproj" />
|
||||
<ProjectReference Include="..\..\modules\Elsa.EntityFrameworkCore.PostgreSql\Elsa.EntityFrameworkCore.PostgreSql.csproj"/>
|
||||
<ProjectReference Include="..\..\modules\Elsa.MassTransit.AzureServiceBus\Elsa.MassTransit.AzureServiceBus.csproj"/>
|
||||
<ProjectReference Include="..\..\modules\Elsa.OpenTelemetry\Elsa.OpenTelemetry.csproj" />
|
||||
<ProjectReference Include="..\..\modules\Elsa\Elsa.csproj"/>
|
||||
<ProjectReference Include="..\..\common\Elsa.DropIns\Elsa.DropIns.csproj"/>
|
||||
<ProjectReference Include="..\..\modules\Elsa.Alterations.MassTransit\Elsa.Alterations.MassTransit.csproj"/>
|
||||
|
|
|
|||
|
|
@ -21,13 +21,17 @@ using Elsa.MongoDb.Modules.Alterations;
|
|||
using Elsa.MongoDb.Modules.Identity;
|
||||
using Elsa.MongoDb.Modules.Management;
|
||||
using Elsa.MongoDb.Modules.Runtime;
|
||||
using Elsa.OpenTelemetry.Middleware;
|
||||
using Elsa.Server.Web;
|
||||
using Elsa.Tenants.Extensions;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Api;
|
||||
using Elsa.Workflows.Management.Compression;
|
||||
using Elsa.Workflows.Management.Stores;
|
||||
using Elsa.Workflows.Pipelines.ActivityExecution;
|
||||
using Elsa.Workflows.Pipelines.WorkflowExecution;
|
||||
using Elsa.Workflows.Runtime.Distributed.Extensions;
|
||||
using Elsa.Workflows.Runtime.Extensions;
|
||||
using Elsa.Workflows.Runtime.Stores;
|
||||
using JetBrains.Annotations;
|
||||
using Medallion.Threading.FileSystem;
|
||||
|
|
@ -133,6 +137,11 @@ services
|
|||
identity.UseConfigurationBasedRoleProvider(options => identitySection.Bind(options));
|
||||
})
|
||||
.UseDefaultAuthentication()
|
||||
.UseWorkflows(workflows =>
|
||||
{
|
||||
workflows.WithDefaultWorkflowExecutionPipeline(pipeline => pipeline.UseWorkflowExecutionTracing());
|
||||
workflows.WithDefaultActivityExecutionPipeline(pipeline => pipeline.UseActivityExecutionTracing());
|
||||
})
|
||||
.UseWorkflowManagement(management =>
|
||||
{
|
||||
if (persistenceProvider == PersistenceProvider.MongoDb)
|
||||
|
|
|
|||
18
src/modules/Elsa.OpenTelemetry/Elsa.OpenTelemetry.csproj
Normal file
18
src/modules/Elsa.OpenTelemetry/Elsa.OpenTelemetry.csproj
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>
|
||||
Provides OpenTelemetry sources for tracing workflow and activity execution.
|
||||
</Description>
|
||||
<PackageTags>elsa module open-telemetry</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Elsa.Workflows.Core\Elsa.Workflows.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Extensions\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
using Elsa.Features.Abstractions;
|
||||
using Elsa.Features.Services;
|
||||
|
||||
namespace Elsa.OpenTelemetry.Features;
|
||||
|
||||
public class OpenTelemetryFeature(IModule module) : FeatureBase(module)
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
}
|
||||
}
|
||||
3
src/modules/Elsa.OpenTelemetry/FodyWeavers.xml
Normal file
3
src/modules/Elsa.OpenTelemetry/FodyWeavers.xml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<ConfigureAwait />
|
||||
</Weavers>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
namespace Elsa.OpenTelemetry.Helpers;
|
||||
|
||||
public class ElsaOpenTelemetry
|
||||
{
|
||||
public static readonly ActivitySource ActivitySource = new("Elsa.Workflows");
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
using System.Diagnostics;
|
||||
using Elsa.OpenTelemetry.Helpers;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Pipelines.ActivityExecution;
|
||||
using Elsa.Workflows.Pipelines.WorkflowExecution;
|
||||
using JetBrains.Annotations;
|
||||
using Activity = System.Diagnostics.Activity;
|
||||
using ActivityKind = System.Diagnostics.ActivityKind;
|
||||
|
||||
namespace Elsa.OpenTelemetry.Middleware;
|
||||
|
||||
[UsedImplicitly]
|
||||
public class OpenTelemetryTracingActivityExecutionMiddleware(ActivityMiddlewareDelegate next) : IActivityExecutionMiddleware
|
||||
{
|
||||
public async ValueTask InvokeAsync(ActivityExecutionContext context)
|
||||
{
|
||||
var activity = context.Activity;
|
||||
using var span = ElsaOpenTelemetry.ActivitySource.StartActivity($"ActivityExecution {context.ActivityDescriptor.TypeName}", ActivityKind.Internal, Activity.Current?.Context ?? default);
|
||||
span?.AddTag("activity.nodeId", activity.NodeId);
|
||||
span?.AddTag("activity.type", activity.Type);
|
||||
span?.AddTag("activity.name", activity.Name);
|
||||
span?.AddTag("activityInstance.id", context.Id);
|
||||
span?.AddTag("activityInstance.originalStatus", context.Status.ToString());
|
||||
span?.AddEvent(new ActivityEvent("Executing"));
|
||||
await next(context);
|
||||
span?.AddEvent(new ActivityEvent("Executed"));
|
||||
span?.AddTag("activityInstance.newStatus", context.Status.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public static class OpenTelemetryTracingActivityExecutionMiddlewareExtensions
|
||||
{
|
||||
/// Installs the <see cref="OpenTelemetryTracingActivityExecutionMiddleware"/> component in the workflow execution pipeline.
|
||||
public static IActivityExecutionPipelineBuilder UseActivityExecutionTracing(this IActivityExecutionPipelineBuilder pipelineBuilder) => pipelineBuilder.Insert<OpenTelemetryTracingActivityExecutionMiddleware>(0);
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
using System.Diagnostics;
|
||||
using Elsa.OpenTelemetry.Helpers;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Pipelines.WorkflowExecution;
|
||||
using JetBrains.Annotations;
|
||||
using Activity = System.Diagnostics.Activity;
|
||||
using ActivityKind = System.Diagnostics.ActivityKind;
|
||||
|
||||
namespace Elsa.OpenTelemetry.Middleware;
|
||||
|
||||
[UsedImplicitly]
|
||||
public class OpenTelemetryTracingWorkflowExecutionMiddleware(WorkflowMiddlewareDelegate next) : WorkflowExecutionMiddleware(next)
|
||||
{
|
||||
public override async ValueTask InvokeAsync(WorkflowExecutionContext context)
|
||||
{
|
||||
var workflowInstanceId = context.Id;
|
||||
var workflow = context.Workflow;
|
||||
using var activity = ElsaOpenTelemetry.ActivitySource.StartActivity($"WorkflowExecution {workflow.WorkflowMetadata.Name}", ActivityKind.Internal, Activity.Current?.Context ?? default);
|
||||
activity?.AddTag("workflowInstance.id", workflowInstanceId);
|
||||
activity?.AddTag("workflowDefinition.definitionId", workflow.Identity.DefinitionId);
|
||||
activity?.AddTag("workflowDefinition.version", workflow.Identity.Version);
|
||||
activity?.AddTag("tenantId", workflow.Identity.TenantId);
|
||||
activity?.AddTag("workflowInstance.originalStatus", context.Status.ToString());
|
||||
activity?.AddTag("workflowInstance.originalSubStatus", context.SubStatus.ToString());
|
||||
activity?.AddEvent(new ActivityEvent("Executing"));
|
||||
await Next(context);
|
||||
activity?.AddEvent(new ActivityEvent("Executed"));
|
||||
activity?.AddTag("workflowInstance.newStatus", context.Status.ToString());
|
||||
activity?.AddTag("workflowInstance.newSubStatus", context.SubStatus.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public static class OpenTelemetryWorkflowExecutionMiddlewareExtensions
|
||||
{
|
||||
/// Installs the <see cref="OpenTelemetryTracingWorkflowExecutionMiddleware"/> component in the workflow execution pipeline.
|
||||
public static IWorkflowExecutionPipelineBuilder UseWorkflowExecutionTracing(this IWorkflowExecutionPipelineBuilder pipelineBuilder) => pipelineBuilder.Insert<OpenTelemetryTracingWorkflowExecutionMiddleware>(0);
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using Elsa.WorkflowContexts.Middleware;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Contracts;
|
||||
using Elsa.Workflows.Pipelines.ActivityExecution;
|
||||
using Elsa.Workflows.Pipelines.WorkflowExecution;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Elsa.Workflows.Contracts;
|
||||
namespace Elsa.Workflows;
|
||||
|
||||
public interface IActivityExecutionMiddleware
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Elsa.Workflows.Pipelines.ActivityExecution;
|
||||
|
||||
namespace Elsa.Workflows.Contracts;
|
||||
namespace Elsa.Workflows;
|
||||
|
||||
/// <summary>
|
||||
/// Builds an activity execution pipeline.
|
||||
|
|
@ -19,6 +19,9 @@ public interface IActivityExecutionPipelineBuilder
|
|||
/// <returns>The current <see cref="IActivityExecutionPipelineBuilder"/>.</returns>
|
||||
IActivityExecutionPipelineBuilder Use(Func<ActivityMiddlewareDelegate, ActivityMiddlewareDelegate> middleware);
|
||||
|
||||
/// Inserts the middleware component at the specified index.
|
||||
IActivityExecutionPipelineBuilder Insert(int index, Func<ActivityMiddlewareDelegate, ActivityMiddlewareDelegate> middleware);
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the final <see cref="ActivityMiddlewareDelegate"/> delegate that invokes each installed middleware component.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,41 +1,30 @@
|
|||
using Elsa.Workflows.Pipelines.WorkflowExecution;
|
||||
|
||||
namespace Elsa.Workflows.Contracts;
|
||||
namespace Elsa.Workflows;
|
||||
|
||||
/// <summary>
|
||||
/// Builds a workflow execution pipeline.
|
||||
/// </summary>
|
||||
public interface IWorkflowExecutionPipelineBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// A general-purpose dictionary of values that can be used by middleware components.
|
||||
/// </summary>
|
||||
public IDictionary<object, object?> Properties { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The middleware components that have been installed.
|
||||
/// </summary>
|
||||
public IEnumerable<Func<WorkflowMiddlewareDelegate, WorkflowMiddlewareDelegate>> Components { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The current service provider to resolve services from.
|
||||
/// </summary>
|
||||
IServiceProvider ServiceProvider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Installs the specified delegate as a middleware component.
|
||||
/// </summary>
|
||||
IWorkflowExecutionPipelineBuilder Use(Func<WorkflowMiddlewareDelegate, WorkflowMiddlewareDelegate> middleware);
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the final <see cref="WorkflowMiddlewareDelegate"/> delegate that invokes each installed middleware component.
|
||||
/// </summary>
|
||||
public WorkflowMiddlewareDelegate Build();
|
||||
|
||||
/// <summary>
|
||||
|
||||
/// Clears the current pipeline.
|
||||
/// </summary>
|
||||
IWorkflowExecutionPipelineBuilder Reset();
|
||||
|
||||
/// Inserts the middleware component at the specified index.
|
||||
IWorkflowExecutionPipelineBuilder Insert(int index, Func<WorkflowMiddlewareDelegate, WorkflowMiddlewareDelegate> middleware);
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the middleware component at the specified index with the specified delegate.
|
||||
|
|
|
|||
|
|
@ -1,20 +1,37 @@
|
|||
using Elsa.Workflows.Contracts;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Workflows.Pipelines.ActivityExecution;
|
||||
|
||||
public static class ActivityExecutionMiddlewareExtensions
|
||||
{
|
||||
public static IActivityExecutionPipelineBuilder UseMiddleware<TMiddleware>(this IActivityExecutionPipelineBuilder pipelineBuilder, params object[] args) where TMiddleware : IActivityExecutionMiddleware
|
||||
public static IActivityExecutionPipelineBuilder UseMiddleware<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TMiddleware>(this IActivityExecutionPipelineBuilder pipelineBuilder, params object[] args) where TMiddleware : IActivityExecutionMiddleware
|
||||
{
|
||||
var delegateFactory = CreateMiddlewareDelegateFactory<TMiddleware>(pipelineBuilder, args);
|
||||
return pipelineBuilder.Use(delegateFactory);
|
||||
}
|
||||
|
||||
public static IActivityExecutionPipelineBuilder Insert<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]TMiddleware>(this IActivityExecutionPipelineBuilder pipelineBuilder, int index, params object[] args) where TMiddleware : IActivityExecutionMiddleware
|
||||
{
|
||||
var delegateFactory = CreateMiddlewareDelegateFactory<TMiddleware>(pipelineBuilder, args);
|
||||
return pipelineBuilder.Insert(index, delegateFactory);
|
||||
}
|
||||
|
||||
/// Creates a middleware delegate for the specified middleware component.
|
||||
public static Func<ActivityMiddlewareDelegate, ActivityMiddlewareDelegate> CreateMiddlewareDelegateFactory<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TMiddleware>(
|
||||
this IActivityExecutionPipelineBuilder pipelineBuilder, params object[] args) where TMiddleware : IActivityExecutionMiddleware
|
||||
{
|
||||
var middleware = typeof(TMiddleware);
|
||||
|
||||
return pipelineBuilder.Use(next =>
|
||||
return next =>
|
||||
{
|
||||
var invokeMethod = MiddlewareHelpers.GetInvokeMethod(middleware);
|
||||
var ctorArgs = new[] { next }.Concat(args).Select(x => x!).ToArray();
|
||||
var ctorArgs = new[]
|
||||
{
|
||||
next
|
||||
}.Concat(args).Select(x => x).ToArray();
|
||||
var instance = ActivatorUtilities.CreateInstance(pipelineBuilder.ServiceProvider, middleware, ctorArgs);
|
||||
return (ActivityMiddlewareDelegate)invokeMethod.CreateDelegate(typeof(ActivityMiddlewareDelegate), instance);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +1,12 @@
|
|||
using Elsa.Workflows.Contracts;
|
||||
|
||||
namespace Elsa.Workflows.Pipelines.ActivityExecution;
|
||||
|
||||
/// <inheritdoc />
|
||||
public class ActivityExecutionPipelinePipelineBuilder : IActivityExecutionPipelineBuilder
|
||||
public class ActivityExecutionPipelinePipelineBuilder(IServiceProvider serviceProvider) : IActivityExecutionPipelineBuilder
|
||||
{
|
||||
private readonly IList<Func<ActivityMiddlewareDelegate, ActivityMiddlewareDelegate>> _components = new List<Func<ActivityMiddlewareDelegate, ActivityMiddlewareDelegate>>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ActivityExecutionPipelinePipelineBuilder"/> class.
|
||||
/// </summary>
|
||||
public ActivityExecutionPipelinePipelineBuilder(IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
public IServiceProvider ServiceProvider { get; } = serviceProvider;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IActivityExecutionPipelineBuilder Use(Func<ActivityMiddlewareDelegate, ActivityMiddlewareDelegate> middleware)
|
||||
|
|
@ -25,6 +15,12 @@ public class ActivityExecutionPipelinePipelineBuilder : IActivityExecutionPipeli
|
|||
return this;
|
||||
}
|
||||
|
||||
public IActivityExecutionPipelineBuilder Insert(int index, Func<ActivityMiddlewareDelegate, ActivityMiddlewareDelegate> middleware)
|
||||
{
|
||||
_components.Insert(index, middleware);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ActivityMiddlewareDelegate Build()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,44 +4,42 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
|
||||
namespace Elsa.Workflows.Pipelines.WorkflowExecution;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extensions to <see cref="IWorkflowExecutionPipelineBuilder"/> that adds support for installing <see cref="IWorkflowExecutionMiddleware"/> components.
|
||||
/// </summary>
|
||||
public static class WorkflowExecutionMiddlewareExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Installs the specified middleware component into the pipeline being built.
|
||||
/// </summary>
|
||||
public static IWorkflowExecutionPipelineBuilder UseMiddleware<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TMiddleware>(
|
||||
this IWorkflowExecutionPipelineBuilder pipelineBuilder, params object[] args) where TMiddleware : IWorkflowExecutionMiddleware
|
||||
{
|
||||
var delegateFactory = CreateMiddlewareDelegateFactory<TMiddleware>(pipelineBuilder, args);
|
||||
return pipelineBuilder.Use(delegateFactory);
|
||||
}
|
||||
|
||||
/// Installs the specified middleware component into the pipeline being built.
|
||||
public static IWorkflowExecutionPipelineBuilder Insert<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TMiddleware>(
|
||||
this IWorkflowExecutionPipelineBuilder pipelineBuilder, int index, params object[] args) where TMiddleware : IWorkflowExecutionMiddleware
|
||||
{
|
||||
var delegateFactory = CreateMiddlewareDelegateFactory<TMiddleware>(pipelineBuilder, args);
|
||||
return pipelineBuilder.Insert(index, delegateFactory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the terminal middleware component with the specified middleware component.
|
||||
/// </summary>
|
||||
public static IWorkflowExecutionPipelineBuilder ReplaceTerminal<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TMiddleware>(
|
||||
this IWorkflowExecutionPipelineBuilder pipelineBuilder, params object[] args) where TMiddleware : IWorkflowExecutionMiddleware
|
||||
{
|
||||
var index = pipelineBuilder.Components.Count() - 1;
|
||||
return pipelineBuilder.Replace<TMiddleware>(index, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
/// Replaces the middleware component at the specified index with the specified middleware component.
|
||||
/// </summary>
|
||||
public static IWorkflowExecutionPipelineBuilder Replace<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TMiddleware>(
|
||||
this IWorkflowExecutionPipelineBuilder pipelineBuilder, int index, params object[] args) where TMiddleware : IWorkflowExecutionMiddleware
|
||||
{
|
||||
var delegateFactory = CreateMiddlewareDelegateFactory<TMiddleware>(pipelineBuilder, args);
|
||||
return pipelineBuilder.Replace(index, delegateFactory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
/// Creates a middleware delegate for the specified middleware component.
|
||||
/// </summary>
|
||||
public static Func<WorkflowMiddlewareDelegate, WorkflowMiddlewareDelegate> CreateMiddlewareDelegateFactory<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TMiddleware>(
|
||||
this IWorkflowExecutionPipelineBuilder pipelineBuilder, params object[] args) where TMiddleware : IWorkflowExecutionMiddleware
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
using Elsa.Workflows.Contracts;
|
||||
|
||||
namespace Elsa.Workflows.Pipelines.WorkflowExecution;
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -54,6 +52,12 @@ public class WorkflowExecutionPipelineBuilder : IWorkflowExecutionPipelineBuilde
|
|||
return this;
|
||||
}
|
||||
|
||||
public IWorkflowExecutionPipelineBuilder Insert(int index, Func<WorkflowMiddlewareDelegate, WorkflowMiddlewareDelegate> middleware)
|
||||
{
|
||||
_components.Insert(index, middleware);
|
||||
return this;
|
||||
}
|
||||
|
||||
public IWorkflowExecutionPipelineBuilder Replace(int index, Func<WorkflowMiddlewareDelegate, WorkflowMiddlewareDelegate> middleware)
|
||||
{
|
||||
_components[index] = middleware;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Contracts;
|
||||
using Elsa.Workflows.Pipelines.ActivityExecution;
|
||||
using Elsa.Workflows.Runtime.Middleware.Activities;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Features;
|
||||
using Elsa.Workflows.Middleware.Activities;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
|
||||
namespace Elsa.Workflows.Runtime.Extensions;
|
||||
|
||||
/// Adds an extension method to the <see cref="WorkflowsFeature"/> that installs a default workflow runtime execution pipeline.
|
||||
public static class PipelineWorkflowsFeatureExtensions
|
||||
{
|
||||
/// Installs a default workflow runtime execution pipeline.
|
||||
public static WorkflowsFeature WithDefaultWorkflowExecutionPipeline(this WorkflowsFeature workflowsFeature, Action<IWorkflowExecutionPipelineBuilder>? configurePipeline = null)
|
||||
{
|
||||
return workflowsFeature.WithWorkflowExecutionPipeline(pipeline =>
|
||||
{
|
||||
pipeline.UseDefaultPipeline();
|
||||
configurePipeline?.Invoke(pipeline);
|
||||
});
|
||||
}
|
||||
|
||||
/// Installs an activity invoker that can run activities asynchronously in the background.
|
||||
public static WorkflowsFeature WithDefaultActivityExecutionPipeline(this WorkflowsFeature workflowsFeature, Action<IActivityExecutionPipelineBuilder>? configurePipeline = null)
|
||||
{
|
||||
return workflowsFeature.WithActivityExecutionPipeline(pipeline =>
|
||||
{
|
||||
pipeline
|
||||
.UseExceptionHandling()
|
||||
.UseExecutionLogging()
|
||||
.UseNotifications()
|
||||
.UseBackgroundActivityInvoker();
|
||||
|
||||
configurePipeline?.Invoke(pipeline);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
using Elsa.Workflows.Contracts;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Middleware.Workflows;
|
||||
using Elsa.Workflows.Pipelines.WorkflowExecution;
|
||||
using Elsa.Workflows.Runtime.Middleware.Workflows;
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Features;
|
||||
using Elsa.Workflows.Middleware.Activities;
|
||||
// ReSharper disable once CheckNamespace
|
||||
|
||||
namespace Elsa.Workflows.Runtime.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Adds an extension method to the <see cref="WorkflowsFeature"/> that installs a default workflow runtime execution pipeline.
|
||||
/// </summary>
|
||||
public static class WorkflowsFeatureExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Installs a default workflow runtime execution pipeline.
|
||||
/// </summary>
|
||||
public static WorkflowsFeature WithDefaultWorkflowExecutionPipeline(this WorkflowsFeature workflowsFeature) =>
|
||||
workflowsFeature.WithWorkflowExecutionPipeline(pipeline =>
|
||||
pipeline.UseDefaultPipeline());
|
||||
|
||||
/// <summary>
|
||||
/// Installs an activity invoker that can run activities asynchronously in the background.
|
||||
/// </summary>
|
||||
public static WorkflowsFeature WithBackgroundActivityExecutionPipeline(this WorkflowsFeature workflowsFeature) =>
|
||||
workflowsFeature.WithActivityExecutionPipeline(pipeline =>
|
||||
pipeline
|
||||
.UseExceptionHandling()
|
||||
.UseExecutionLogging()
|
||||
.UseNotifications()
|
||||
.UseBackgroundActivityInvoker());
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Contracts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public class ElsaFeature : FeatureBase
|
|||
Module
|
||||
.UseWorkflows(workflows => workflows
|
||||
.WithDefaultWorkflowExecutionPipeline()
|
||||
.WithBackgroundActivityExecutionPipeline())
|
||||
.WithDefaultActivityExecutionPipeline())
|
||||
.UseWorkflowManagement(management =>
|
||||
{
|
||||
if (!DisableAutomaticActivityRegistration)
|
||||
|
|
|
|||
Loading…
Reference in a new issue