Add OpenTelemetry support for tracing workflow execution
This commit introduces the Elsa.OpenTelemetry module to provide OpenTelemetry sources for tracing workflow and activity execution. Additionally, it updates the program to include default workflow and activity execution pipelines with tracing middleware, and improves pipeline builder extensions to support middleware insertion.
This commit is contained in:
parent
53172cded9
commit
79b5bfc378
4
.github/workflows/elsa-server-and-studio.yml
vendored
4
.github/workflows/elsa-server-and-studio.yml
vendored
|
|
@ -3,7 +3,7 @@ on:
|
|||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- patch/3.2.x
|
||||
- blueberry
|
||||
|
||||
jobs:
|
||||
push_to_registry:
|
||||
|
|
@ -29,7 +29,7 @@ jobs:
|
|||
with:
|
||||
# list of Docker images to use as base name for tags
|
||||
images: |
|
||||
elsaworkflows/elsa-server-and-studio-v3-2-1-preview
|
||||
elsaworkflows/elsa-server-and-studio-v3-2-1-blueberry
|
||||
flavor: |
|
||||
latest=true
|
||||
# generate Docker tags based on the following events/attributes
|
||||
|
|
|
|||
4
.github/workflows/elsa-server.yml
vendored
4
.github/workflows/elsa-server.yml
vendored
|
|
@ -3,7 +3,7 @@ on:
|
|||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- patch/3.2.x
|
||||
- blueberry
|
||||
|
||||
jobs:
|
||||
push_to_registry:
|
||||
|
|
@ -29,7 +29,7 @@ jobs:
|
|||
with:
|
||||
# list of Docker images to use as base name for tags
|
||||
images: |
|
||||
elsaworkflows/elsa-server-v3-2-1-preview
|
||||
elsaworkflows/elsa-server-v3-2-1-blueberry
|
||||
flavor: |
|
||||
latest=true
|
||||
# generate Docker tags based on the following events/attributes
|
||||
|
|
|
|||
4
.github/workflows/elsa-studio.yml
vendored
4
.github/workflows/elsa-studio.yml
vendored
|
|
@ -3,7 +3,7 @@ on:
|
|||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- patch/3.2.x
|
||||
- blueberry
|
||||
|
||||
jobs:
|
||||
push_to_registry:
|
||||
|
|
@ -29,7 +29,7 @@ jobs:
|
|||
with:
|
||||
# list of Docker images to use as base name for tags
|
||||
images: |
|
||||
elsaworkflows/elsa-studio-v3-2-1-preview
|
||||
elsaworkflows/elsa-studio-v3-2-1-blueberry
|
||||
flavor: |
|
||||
latest=true
|
||||
# generate Docker tags based on the following events/attributes
|
||||
|
|
|
|||
15
.github/workflows/packages.yml
vendored
15
.github/workflows/packages.yml
vendored
|
|
@ -3,18 +3,7 @@ on:
|
|||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'feature/*'
|
||||
- 'feat/*'
|
||||
- 'issue/*'
|
||||
- 'bug/*'
|
||||
- 'enhancement/*'
|
||||
- 'enh/*'
|
||||
- 'patch/*'
|
||||
- 'fix/*'
|
||||
- 'perf/*'
|
||||
- 'hotfix/*'
|
||||
- 'chore/*'
|
||||
- 'blueberry'
|
||||
release:
|
||||
types: [ prereleased, published ]
|
||||
env:
|
||||
|
|
@ -62,7 +51,7 @@ jobs:
|
|||
TAG_NAME=${TAG_NAME#refs/tags/} # remove the refs/tags/ prefix
|
||||
echo "VERSION=${TAG_NAME}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "VERSION=3.2.1-preview.${{github.run_number}}" >> $GITHUB_ENV
|
||||
echo "VERSION=3.2.1-blueberry.${{github.run_number}}" >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v2
|
||||
|
|
|
|||
7
Elsa.sln
7
Elsa.sln
|
|
@ -355,6 +355,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Workflows.PerformanceT
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.MongoDb.UnitTests", "test\unit\Elsa.MongoDb.UnitTests\Elsa.MongoDb.UnitTests.csproj", "{56CAA9F2-1882-4EFA-BAC0-9C3D804553F1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.OpenTelemetry", "src\modules\Elsa.OpenTelemetry\Elsa.OpenTelemetry.csproj", "{25880971-403E-4872-93A1-D33089E07C91}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -844,6 +846,10 @@ Global
|
|||
{56CAA9F2-1882-4EFA-BAC0-9C3D804553F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{56CAA9F2-1882-4EFA-BAC0-9C3D804553F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{56CAA9F2-1882-4EFA-BAC0-9C3D804553F1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{25880971-403E-4872-93A1-D33089E07C91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{25880971-403E-4872-93A1-D33089E07C91}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{25880971-403E-4872-93A1-D33089E07C91}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{25880971-403E-4872-93A1-D33089E07C91}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -991,6 +997,7 @@ Global
|
|||
{CBB515F3-A0EF-43B5-A907-FD4E652DD66E} = {90031D64-CA0F-46D0-9AF4-8DC023A5FFCD}
|
||||
{90CD37A9-C866-4D90-A3B1-8C87F53B845E} = {CBB515F3-A0EF-43B5-A907-FD4E652DD66E}
|
||||
{56CAA9F2-1882-4EFA-BAC0-9C3D804553F1} = {18453B51-25EB-4317-A4B3-B10518252E92}
|
||||
{25880971-403E-4872-93A1-D33089E07C91} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {D4B5CEAA-7D70-4FCB-A68E-B03FBE5E0E5E}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,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="..\Elsa\Elsa.csproj"/>
|
||||
<ProjectReference Include="..\..\common\Elsa.DropIns\Elsa.DropIns.csproj"/>
|
||||
<ProjectReference Include="..\..\modules\Elsa.Alterations.MassTransit\Elsa.Alterations.MassTransit.csproj"/>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ 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.Workflows;
|
||||
using Elsa.Workflows.Management.Compression;
|
||||
|
|
@ -131,6 +132,11 @@ services
|
|||
identity.UseConfigurationBasedRoleProvider(options => identitySection.Bind(options));
|
||||
})
|
||||
.UseDefaultAuthentication()
|
||||
.UseWorkflows(workflows =>
|
||||
{
|
||||
workflows.WithDefaultWorkflowExecutionPipeline(pipeline => pipeline.UseWorkflowExecutionTracing());
|
||||
workflows.WithDefaultActivityExecutionPipeline(pipeline => pipeline.UseActivityExecutionTracing());
|
||||
})
|
||||
.UseWorkflowManagement(management =>
|
||||
{
|
||||
if (useMongoDb)
|
||||
|
|
|
|||
14
src/modules/Elsa.OpenTelemetry/Elsa.OpenTelemetry.csproj
Normal file
14
src/modules/Elsa.OpenTelemetry/Elsa.OpenTelemetry.csproj
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<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>
|
||||
|
||||
</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,42 @@
|
|||
using System.Diagnostics;
|
||||
using Elsa.OpenTelemetry.Helpers;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Contracts;
|
||||
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;
|
||||
|
||||
/// <inheritdoc />
|
||||
[UsedImplicitly]
|
||||
public class OpenTelemetryTracingActivityExecutionMiddleware(ActivityMiddlewareDelegate next) : IActivityExecutionMiddleware
|
||||
{
|
||||
/// <inheritdoc />
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="OpenTelemetryTracingActivityExecutionMiddleware"/>.
|
||||
/// </summary>
|
||||
[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,49 @@
|
|||
using System.Diagnostics;
|
||||
using Elsa.OpenTelemetry.Helpers;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Contracts;
|
||||
using Elsa.Workflows.Pipelines.WorkflowExecution;
|
||||
using JetBrains.Annotations;
|
||||
using Activity = System.Diagnostics.Activity;
|
||||
using ActivityKind = System.Diagnostics.ActivityKind;
|
||||
|
||||
namespace Elsa.OpenTelemetry.Middleware;
|
||||
|
||||
/// <summary>
|
||||
/// Middleware that traces workflow execution using OpenTelemetry.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class OpenTelemetryTracingWorkflowExecutionMiddleware(WorkflowMiddlewareDelegate next) : WorkflowExecutionMiddleware(next)
|
||||
{
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(context.CorrelationId))
|
||||
activity?.AddTag("correlationId", context.CorrelationId);
|
||||
|
||||
activity?.AddTag("workflowInstance.id", workflowInstanceId);
|
||||
activity?.AddTag("workflowDefinition.definitionId", workflow.Identity.DefinitionId);
|
||||
activity?.AddTag("workflowDefinition.version", workflow.Identity.Version);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="OpenTelemetryTracingWorkflowExecutionMiddleware"/>.
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ public interface IWorkflowExecutionPipelineBuilder
|
|||
/// 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,3 +1,4 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using Elsa.Workflows.Contracts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
|
@ -5,16 +6,33 @@ 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);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,13 @@ public class ActivityExecutionPipelinePipelineBuilder : IActivityExecutionPipeli
|
|||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -54,6 +54,14 @@ public class WorkflowExecutionPipelineBuilder : IWorkflowExecutionPipelineBuilde
|
|||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IWorkflowExecutionPipelineBuilder Insert(int index, Func<WorkflowMiddlewareDelegate, WorkflowMiddlewareDelegate> middleware)
|
||||
{
|
||||
_components.Insert(index, middleware);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IWorkflowExecutionPipelineBuilder Replace(int index, Func<WorkflowMiddlewareDelegate, WorkflowMiddlewareDelegate> middleware)
|
||||
{
|
||||
_components[index] = middleware;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
using Elsa.Workflows.Contracts;
|
||||
using Elsa.Workflows.Features;
|
||||
using Elsa.Workflows.Middleware.Activities;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ using Elsa.Workflows.Middleware.Activities;
|
|||
// ReSharper disable once CheckNamespace
|
||||
using Elsa.Workflows.Features;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.Extensions;
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
Loading…
Reference in a new issue