diff --git a/.github/workflows/elsa-server-and-studio.yml b/.github/workflows/elsa-server-and-studio.yml
index 8f58dbcc2..cbca2daf3 100644
--- a/.github/workflows/elsa-server-and-studio.yml
+++ b/.github/workflows/elsa-server-and-studio.yml
@@ -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
diff --git a/.github/workflows/elsa-server.yml b/.github/workflows/elsa-server.yml
index 82a92a31b..e305d5072 100644
--- a/.github/workflows/elsa-server.yml
+++ b/.github/workflows/elsa-server.yml
@@ -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
diff --git a/.github/workflows/elsa-studio.yml b/.github/workflows/elsa-studio.yml
index a8673a0dd..a275af27d 100644
--- a/.github/workflows/elsa-studio.yml
+++ b/.github/workflows/elsa-studio.yml
@@ -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
diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml
index c4461693c..2869399e3 100644
--- a/.github/workflows/packages.yml
+++ b/.github/workflows/packages.yml
@@ -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
diff --git a/Elsa.sln b/Elsa.sln
index 3d9bca0c0..58f882779 100644
--- a/Elsa.sln
+++ b/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}
diff --git a/src/bundles/Elsa.Server.Web/Elsa.Server.Web.csproj b/src/bundles/Elsa.Server.Web/Elsa.Server.Web.csproj
index 71cb87c96..ff8b01a9d 100644
--- a/src/bundles/Elsa.Server.Web/Elsa.Server.Web.csproj
+++ b/src/bundles/Elsa.Server.Web/Elsa.Server.Web.csproj
@@ -12,6 +12,7 @@
+
diff --git a/src/bundles/Elsa.Server.Web/Program.cs b/src/bundles/Elsa.Server.Web/Program.cs
index 33328dace..d72e04aca 100644
--- a/src/bundles/Elsa.Server.Web/Program.cs
+++ b/src/bundles/Elsa.Server.Web/Program.cs
@@ -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)
diff --git a/src/modules/Elsa.OpenTelemetry/Elsa.OpenTelemetry.csproj b/src/modules/Elsa.OpenTelemetry/Elsa.OpenTelemetry.csproj
new file mode 100644
index 000000000..dc06e309b
--- /dev/null
+++ b/src/modules/Elsa.OpenTelemetry/Elsa.OpenTelemetry.csproj
@@ -0,0 +1,14 @@
+
+
+
+
+ Provides OpenTelemetry sources for tracing workflow and activity execution.
+
+ elsa module open-telemetry
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/Elsa.OpenTelemetry/Features/OpenTelemetryFeature.cs b/src/modules/Elsa.OpenTelemetry/Features/OpenTelemetryFeature.cs
new file mode 100644
index 000000000..67201c44d
--- /dev/null
+++ b/src/modules/Elsa.OpenTelemetry/Features/OpenTelemetryFeature.cs
@@ -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()
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.OpenTelemetry/FodyWeavers.xml b/src/modules/Elsa.OpenTelemetry/FodyWeavers.xml
new file mode 100644
index 000000000..00e1d9a1c
--- /dev/null
+++ b/src/modules/Elsa.OpenTelemetry/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/src/modules/Elsa.OpenTelemetry/Helpers/OpenTelemetryHelpers.cs b/src/modules/Elsa.OpenTelemetry/Helpers/OpenTelemetryHelpers.cs
new file mode 100644
index 000000000..302659456
--- /dev/null
+++ b/src/modules/Elsa.OpenTelemetry/Helpers/OpenTelemetryHelpers.cs
@@ -0,0 +1,8 @@
+using System.Diagnostics;
+
+namespace Elsa.OpenTelemetry.Helpers;
+
+public class ElsaOpenTelemetry
+{
+ public static readonly ActivitySource ActivitySource = new("Elsa.Workflows");
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.OpenTelemetry/Middleware/OpenTelemetryTracingActivityExecutionMiddleware.cs b/src/modules/Elsa.OpenTelemetry/Middleware/OpenTelemetryTracingActivityExecutionMiddleware.cs
new file mode 100644
index 000000000..cd389bdb7
--- /dev/null
+++ b/src/modules/Elsa.OpenTelemetry/Middleware/OpenTelemetryTracingActivityExecutionMiddleware.cs
@@ -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;
+
+///
+[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());
+ }
+}
+
+///
+/// Contains extension methods for .
+///
+[UsedImplicitly]
+public static class OpenTelemetryTracingActivityExecutionMiddlewareExtensions
+{
+ /// Installs the component in the workflow execution pipeline.
+ public static IActivityExecutionPipelineBuilder UseActivityExecutionTracing(this IActivityExecutionPipelineBuilder pipelineBuilder) => pipelineBuilder.Insert(0);
+}
diff --git a/src/modules/Elsa.OpenTelemetry/Middleware/OpenTelemetryTracingWorkflowExecutionMiddleware.cs b/src/modules/Elsa.OpenTelemetry/Middleware/OpenTelemetryTracingWorkflowExecutionMiddleware.cs
new file mode 100644
index 000000000..ae6d67572
--- /dev/null
+++ b/src/modules/Elsa.OpenTelemetry/Middleware/OpenTelemetryTracingWorkflowExecutionMiddleware.cs
@@ -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;
+
+///
+/// Middleware that traces workflow execution using OpenTelemetry.
+///
+[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);
+
+ 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());
+ }
+}
+
+///
+/// Contains extension methods for .
+///
+[UsedImplicitly]
+public static class OpenTelemetryWorkflowExecutionMiddlewareExtensions
+{
+ /// Installs the component in the workflow execution pipeline.
+ public static IWorkflowExecutionPipelineBuilder UseWorkflowExecutionTracing(this IWorkflowExecutionPipelineBuilder pipelineBuilder) => pipelineBuilder.Insert(0);
+}
diff --git a/src/modules/Elsa.Workflows.Core/Contracts/IActivityExecutionPipelineBuilder.cs b/src/modules/Elsa.Workflows.Core/Contracts/IActivityExecutionPipelineBuilder.cs
index 7c7968451..6cf6c926d 100644
--- a/src/modules/Elsa.Workflows.Core/Contracts/IActivityExecutionPipelineBuilder.cs
+++ b/src/modules/Elsa.Workflows.Core/Contracts/IActivityExecutionPipelineBuilder.cs
@@ -19,6 +19,9 @@ public interface IActivityExecutionPipelineBuilder
/// The current .
IActivityExecutionPipelineBuilder Use(Func middleware);
+ /// Inserts the middleware component at the specified index.
+ IActivityExecutionPipelineBuilder Insert(int index, Func middleware);
+
///
/// Constructs the final delegate that invokes each installed middleware component.
///
diff --git a/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowExecutionPipelineBuilder.cs b/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowExecutionPipelineBuilder.cs
index a2f37c9b0..04ce5ff62 100644
--- a/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowExecutionPipelineBuilder.cs
+++ b/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowExecutionPipelineBuilder.cs
@@ -36,6 +36,9 @@ public interface IWorkflowExecutionPipelineBuilder
/// Clears the current pipeline.
///
IWorkflowExecutionPipelineBuilder Reset();
+
+ /// Inserts the middleware component at the specified index.
+ IWorkflowExecutionPipelineBuilder Insert(int index, Func middleware);
///
/// Replaces the middleware component at the specified index with the specified delegate.
diff --git a/src/modules/Elsa.Workflows.Core/Pipelines/ActivityExecution/ActivityExecutionMiddlewareExtensions.cs b/src/modules/Elsa.Workflows.Core/Pipelines/ActivityExecution/ActivityExecutionMiddlewareExtensions.cs
index 487b41340..c42152859 100644
--- a/src/modules/Elsa.Workflows.Core/Pipelines/ActivityExecution/ActivityExecutionMiddlewareExtensions.cs
+++ b/src/modules/Elsa.Workflows.Core/Pipelines/ActivityExecution/ActivityExecutionMiddlewareExtensions.cs
@@ -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(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(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(pipelineBuilder, args);
+ return pipelineBuilder.Insert(index, delegateFactory);
+ }
+
+ /// Creates a middleware delegate for the specified middleware component.
+ public static Func 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);
- });
+ };
}
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Pipelines/ActivityExecution/ActivityExecutionPipelinePipelineBuilder.cs b/src/modules/Elsa.Workflows.Core/Pipelines/ActivityExecution/ActivityExecutionPipelinePipelineBuilder.cs
index 971ebfbca..b64289f03 100644
--- a/src/modules/Elsa.Workflows.Core/Pipelines/ActivityExecution/ActivityExecutionPipelinePipelineBuilder.cs
+++ b/src/modules/Elsa.Workflows.Core/Pipelines/ActivityExecution/ActivityExecutionPipelinePipelineBuilder.cs
@@ -25,6 +25,13 @@ public class ActivityExecutionPipelinePipelineBuilder : IActivityExecutionPipeli
return this;
}
+ ///
+ public IActivityExecutionPipelineBuilder Insert(int index, Func middleware)
+ {
+ _components.Insert(index, middleware);
+ return this;
+ }
+
///
public ActivityMiddlewareDelegate Build()
{
diff --git a/src/modules/Elsa.Workflows.Core/Pipelines/WorkflowExecution/WorkflowExecutionMiddlewareExtensions.cs b/src/modules/Elsa.Workflows.Core/Pipelines/WorkflowExecution/WorkflowExecutionMiddlewareExtensions.cs
index 4e7221c11..4007c8a16 100644
--- a/src/modules/Elsa.Workflows.Core/Pipelines/WorkflowExecution/WorkflowExecutionMiddlewareExtensions.cs
+++ b/src/modules/Elsa.Workflows.Core/Pipelines/WorkflowExecution/WorkflowExecutionMiddlewareExtensions.cs
@@ -4,44 +4,42 @@ using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Workflows.Pipelines.WorkflowExecution;
-///
/// Provides extensions to that adds support for installing components.
-///
public static class WorkflowExecutionMiddlewareExtensions
{
- ///
/// Installs the specified middleware component into the pipeline being built.
- ///
public static IWorkflowExecutionPipelineBuilder UseMiddleware<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TMiddleware>(
this IWorkflowExecutionPipelineBuilder pipelineBuilder, params object[] args) where TMiddleware : IWorkflowExecutionMiddleware
{
var delegateFactory = CreateMiddlewareDelegateFactory(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(pipelineBuilder, args);
+ return pipelineBuilder.Insert(index, delegateFactory);
+ }
- ///
/// Replaces the terminal middleware component with the specified middleware component.
- ///
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(index, args);
}
-
- ///
+
/// Replaces the middleware component at the specified index with the specified middleware component.
- ///
public static IWorkflowExecutionPipelineBuilder Replace<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TMiddleware>(
this IWorkflowExecutionPipelineBuilder pipelineBuilder, int index, params object[] args) where TMiddleware : IWorkflowExecutionMiddleware
{
var delegateFactory = CreateMiddlewareDelegateFactory(pipelineBuilder, args);
return pipelineBuilder.Replace(index, delegateFactory);
}
-
- ///
+
/// Creates a middleware delegate for the specified middleware component.
- ///
public static Func CreateMiddlewareDelegateFactory<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TMiddleware>(
this IWorkflowExecutionPipelineBuilder pipelineBuilder, params object[] args) where TMiddleware : IWorkflowExecutionMiddleware
{
diff --git a/src/modules/Elsa.Workflows.Core/Pipelines/WorkflowExecution/WorkflowExecutionPipelineBuilder.cs b/src/modules/Elsa.Workflows.Core/Pipelines/WorkflowExecution/WorkflowExecutionPipelineBuilder.cs
index c61c6c4e5..940461e8f 100644
--- a/src/modules/Elsa.Workflows.Core/Pipelines/WorkflowExecution/WorkflowExecutionPipelineBuilder.cs
+++ b/src/modules/Elsa.Workflows.Core/Pipelines/WorkflowExecution/WorkflowExecutionPipelineBuilder.cs
@@ -54,6 +54,14 @@ public class WorkflowExecutionPipelineBuilder : IWorkflowExecutionPipelineBuilde
return this;
}
+ ///
+ public IWorkflowExecutionPipelineBuilder Insert(int index, Func middleware)
+ {
+ _components.Insert(index, middleware);
+ return this;
+ }
+
+ ///
public IWorkflowExecutionPipelineBuilder Replace(int index, Func middleware)
{
_components[index] = middleware;
diff --git a/src/modules/Elsa.Workflows.Runtime/Extensions/PipelineWorkflowsFeatureExtensions.cs b/src/modules/Elsa.Workflows.Runtime/Extensions/PipelineWorkflowsFeatureExtensions.cs
new file mode 100644
index 000000000..b68a86779
--- /dev/null
+++ b/src/modules/Elsa.Workflows.Runtime/Extensions/PipelineWorkflowsFeatureExtensions.cs
@@ -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 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? 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? configurePipeline = null)
+ {
+ return workflowsFeature.WithActivityExecutionPipeline(pipeline =>
+ {
+ pipeline
+ .UseExceptionHandling()
+ .UseExecutionLogging()
+ .UseNotifications()
+ .UseBackgroundActivityInvoker();
+
+ configurePipeline?.Invoke(pipeline);
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Runtime/Extensions/WorkflowsFeatureExtensions.cs b/src/modules/Elsa.Workflows.Runtime/Extensions/WorkflowsFeatureExtensions.cs
index 9d8bda420..7031ca4a1 100644
--- a/src/modules/Elsa.Workflows.Runtime/Extensions/WorkflowsFeatureExtensions.cs
+++ b/src/modules/Elsa.Workflows.Runtime/Extensions/WorkflowsFeatureExtensions.cs
@@ -6,6 +6,7 @@ using Elsa.Workflows.Middleware.Activities;
// ReSharper disable once CheckNamespace
using Elsa.Workflows.Features;
+// ReSharper disable once CheckNamespace
namespace Elsa.Extensions;
///