Skip to content

Commit 6c10082

Browse files
authored
Merge branch 'master' into efcore-ver-increment-mysql-migrations
2 parents a15499e + 1f21b41 commit 6c10082

37 files changed

+860
-118
lines changed

ReleaseNotes/1.6.9.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Workflow Core 1.6.9
2+
3+
This release adds functionality to subscribe to workflow life cycle events (WorkflowStarted, WorkflowComplete, WorkflowError, WorkflowSuspended, WorkflowResumed, StepStarted, StepCompleted, etc...)
4+
This can be achieved by either grabbing the `ILifeCycleEventHub` implementation from the IoC container and subscribing to events there, or attach an event on the workflow host class `IWorkflowHost.OnLifeCycleEvent`.
5+
This implementation only publishes events to the local node... we will still need to implement a distributed version of the EventHub to solve the problem for multi-node clusters.

WorkflowCore.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ReleaseNotes", "ReleaseNote
9393
ReleaseNotes\1.6.0.md = ReleaseNotes\1.6.0.md
9494
ReleaseNotes\1.6.6.md = ReleaseNotes\1.6.6.md
9595
ReleaseNotes\1.6.8.md = ReleaseNotes\1.6.8.md
96+
ReleaseNotes\1.6.9.md = ReleaseNotes\1.6.9.md
9697
EndProjectSection
9798
EndProject
9899
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WorkflowCore.Sample14", "src\samples\WorkflowCore.Sample14\WorkflowCore.Sample14.csproj", "{6BC66637-B42A-4334-ADFB-DBEC9F29D293}"

src/WorkflowCore/Interface/IExecutionResultProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace WorkflowCore.Interface
55
{
66
public interface IExecutionResultProcessor
77
{
8-
void HandleStepException(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer pointer, WorkflowStep step);
8+
void HandleStepException(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer pointer, WorkflowStep step, Exception exception);
99
void ProcessExecutionResult(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer pointer, WorkflowStep step, ExecutionResult result, WorkflowExecutorResult workflowResult);
1010
}
1111
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using System.Threading.Tasks;
5+
using WorkflowCore.Models.LifeCycleEvents;
6+
7+
namespace WorkflowCore.Interface
8+
{
9+
public interface ILifeCycleEventHub
10+
{
11+
Task PublishNotification(LifeCycleEvent evt);
12+
void Subscribe(Action<LifeCycleEvent> action);
13+
}
14+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using WorkflowCore.Models.LifeCycleEvents;
5+
6+
namespace WorkflowCore.Interface
7+
{
8+
public interface ILifeCycleEventPublisher : IBackgroundTask
9+
{
10+
void PublishNotification(LifeCycleEvent evt);
11+
}
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using WorkflowCore.Models;
5+
6+
namespace WorkflowCore.Interface
7+
{
8+
public interface IWorkflowErrorHandler
9+
{
10+
WorkflowErrorHandling Type { get; }
11+
void Handle(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer pointer, WorkflowStep step, Exception exception, Queue<ExecutionPointer> bubbleUpQueue);
12+
}
13+
}

src/WorkflowCore/Interface/IWorkflowHost.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System;
33
using System.Threading.Tasks;
44
using WorkflowCore.Models;
5+
using WorkflowCore.Models.LifeCycleEvents;
56

67
namespace WorkflowCore.Interface
78
{
@@ -19,6 +20,7 @@ public interface IWorkflowHost : IWorkflowController
1920

2021

2122
event StepErrorEventHandler OnStepError;
23+
event LifeCycleEventHandler OnLifeCycleEvent;
2224
void ReportStepError(WorkflowInstance workflow, WorkflowStep step, Exception exception);
2325

2426
//public dependencies to allow for extension method access
@@ -32,4 +34,5 @@ public interface IWorkflowHost : IWorkflowController
3234
}
3335

3436
public delegate void StepErrorEventHandler(WorkflowInstance workflow, WorkflowStep step, Exception exception);
35-
}
37+
public delegate void LifeCycleEventHandler(LifeCycleEvent evt);
38+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace WorkflowCore.Models.LifeCycleEvents
6+
{
7+
public abstract class LifeCycleEvent
8+
{
9+
public DateTime EventTimeUtc { get; set; }
10+
11+
public string WorkflowInstanceId { get; set; }
12+
13+
public string WorkflowDefinitionId { get; set; }
14+
15+
public int Version { get; set; }
16+
17+
public string Reference { get; set; }
18+
}
19+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace WorkflowCore.Models.LifeCycleEvents
6+
{
7+
public class StepCompleted : LifeCycleEvent
8+
{
9+
public string ExecutionPointerId { get; set; }
10+
11+
public int StepId { get; set; }
12+
}
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace WorkflowCore.Models.LifeCycleEvents
6+
{
7+
public class StepStarted : LifeCycleEvent
8+
{
9+
public string ExecutionPointerId { get; set; }
10+
11+
public int StepId { get; set; }
12+
}
13+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace WorkflowCore.Models.LifeCycleEvents
6+
{
7+
public class WorkflowCompleted : LifeCycleEvent
8+
{
9+
}
10+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace WorkflowCore.Models.LifeCycleEvents
6+
{
7+
public class WorkflowError : LifeCycleEvent
8+
{
9+
public string Message { get; set; }
10+
11+
public string ExecutionPointerId { get; set; }
12+
13+
public int StepId { get; set; }
14+
}
15+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace WorkflowCore.Models.LifeCycleEvents
6+
{
7+
public class WorkflowResumed : LifeCycleEvent
8+
{
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace WorkflowCore.Models.LifeCycleEvents
6+
{
7+
public class WorkflowStarted : LifeCycleEvent
8+
{
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace WorkflowCore.Models.LifeCycleEvents
6+
{
7+
public class WorkflowSuspended : LifeCycleEvent
8+
{
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace WorkflowCore.Models.LifeCycleEvents
6+
{
7+
public class WorkflowTerminated : LifeCycleEvent
8+
{
9+
}
10+
}

src/WorkflowCore/Models/WorkflowOptions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.Extensions.DependencyInjection;
22
using System;
3+
using Microsoft.Extensions.Logging;
34
using WorkflowCore.Interface;
45
using WorkflowCore.Services;
56

@@ -10,6 +11,7 @@ public class WorkflowOptions
1011
internal Func<IServiceProvider, IPersistenceProvider> PersistanceFactory;
1112
internal Func<IServiceProvider, IQueueProvider> QueueFactory;
1213
internal Func<IServiceProvider, IDistributedLockProvider> LockFactory;
14+
internal Func<IServiceProvider, ILifeCycleEventHub> EventHubFactory;
1315
internal TimeSpan PollInterval;
1416
internal TimeSpan IdleTime;
1517
internal TimeSpan ErrorRetryInterval;
@@ -26,6 +28,7 @@ public WorkflowOptions(IServiceCollection services)
2628
QueueFactory = new Func<IServiceProvider, IQueueProvider>(sp => new SingleNodeQueueProvider());
2729
LockFactory = new Func<IServiceProvider, IDistributedLockProvider>(sp => new SingleNodeLockProvider());
2830
PersistanceFactory = new Func<IServiceProvider, IPersistenceProvider>(sp => new MemoryPersistenceProvider());
31+
EventHubFactory = new Func<IServiceProvider, ILifeCycleEventHub>(sp => new SingleNodeEventHub(sp.GetService<ILoggerFactory>()));
2932
}
3033

3134
public void UsePersistence(Func<IServiceProvider, IPersistenceProvider> factory)
@@ -43,6 +46,11 @@ public void UseQueueProvider(Func<IServiceProvider, IQueueProvider> factory)
4346
QueueFactory = factory;
4447
}
4548

49+
public void UseEventHub(Func<IServiceProvider, ILifeCycleEventHub> factory)
50+
{
51+
EventHubFactory = factory;
52+
}
53+
4654
public void UsePollInterval(TimeSpan interval)
4755
{
4856
PollInterval = interval;

src/WorkflowCore/ServiceCollectionExtensions.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using WorkflowCore.Primitives;
1212
using WorkflowCore.Services.BackgroundTasks;
1313
using WorkflowCore.Services.DefinitionStorage;
14+
using WorkflowCore.Services.ErrorHandlers;
1415

1516
namespace Microsoft.Extensions.DependencyInjection
1617
{
@@ -26,12 +27,20 @@ public static IServiceCollection AddWorkflow(this IServiceCollection services, A
2627
services.AddTransient<IPersistenceProvider>(options.PersistanceFactory);
2728
services.AddSingleton<IQueueProvider>(options.QueueFactory);
2829
services.AddSingleton<IDistributedLockProvider>(options.LockFactory);
30+
services.AddSingleton<ILifeCycleEventHub>(options.EventHubFactory);
2931
services.AddSingleton<IWorkflowRegistry, WorkflowRegistry>();
3032
services.AddSingleton<WorkflowOptions>(options);
33+
services.AddSingleton<ILifeCycleEventPublisher, LifeCycleEventPublisher>();
3134

3235
services.AddTransient<IBackgroundTask, WorkflowConsumer>();
3336
services.AddTransient<IBackgroundTask, EventConsumer>();
3437
services.AddTransient<IBackgroundTask, RunnablePoller>();
38+
services.AddTransient<IBackgroundTask>(sp => sp.GetService<ILifeCycleEventPublisher>());
39+
40+
services.AddTransient<IWorkflowErrorHandler, CompensateHandler>();
41+
services.AddTransient<IWorkflowErrorHandler, RetryHandler>();
42+
services.AddTransient<IWorkflowErrorHandler, TerminateHandler>();
43+
services.AddTransient<IWorkflowErrorHandler, SuspendHandler>();
3544

3645
services.AddSingleton<IWorkflowController, WorkflowController>();
3746
services.AddSingleton<IWorkflowHost, WorkflowHost>();
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using System.Threading.Tasks;
5+
using Microsoft.Extensions.Logging;
6+
using WorkflowCore.Interface;
7+
using WorkflowCore.Models.LifeCycleEvents;
8+
9+
namespace WorkflowCore.Services
10+
{
11+
public class SingleNodeEventHub : ILifeCycleEventHub
12+
{
13+
private ICollection<Action<LifeCycleEvent>> _subscribers = new HashSet<Action<LifeCycleEvent>>();
14+
private readonly ILogger _logger;
15+
16+
public SingleNodeEventHub(ILoggerFactory loggerFactory)
17+
{
18+
_logger = loggerFactory.CreateLogger<SingleNodeEventHub>();
19+
}
20+
21+
public Task PublishNotification(LifeCycleEvent evt)
22+
{
23+
Task.Run(() =>
24+
{
25+
foreach (var subscriber in _subscribers)
26+
{
27+
try
28+
{
29+
subscriber(evt);
30+
}
31+
catch (Exception ex)
32+
{
33+
_logger.LogWarning(default(EventId), ex, $"Error on event subscriber: {ex.Message}");
34+
}
35+
}
36+
});
37+
return Task.CompletedTask;
38+
}
39+
40+
public void Subscribe(Action<LifeCycleEvent> action)
41+
{
42+
_subscribers.Add(action);
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)