Skip to content

Commit 3a9d7fe

Browse files
authored
Merge pull request #55 from danielgerlag/interface-speration
Interface separation
2 parents bd80523 + 768ae3f commit 3a9d7fe

File tree

8 files changed

+285
-171
lines changed

8 files changed

+285
-171
lines changed

ReleaseNotes/1.3.2.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Workflow Core 1.3.2
2+
3+
* Added `WorkflowController` service
4+
5+
Use the `WorkflowController` service to control workflows without having to run an exection node.
6+
7+
```c#
8+
var controller = serviceProvider.GetService<IWorkflowController>();
9+
```
10+
11+
## Exposed methods
12+
* StartWorkflow
13+
* PublishEvent
14+
* RegisterWorkflow
15+
* SuspendWorkflow
16+
* ResumeWorkflow
17+
* TerminateWorkflow
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using System.Threading.Tasks;
5+
6+
namespace WorkflowCore.Interface
7+
{
8+
public interface IWorkflowController
9+
{
10+
Task<string> StartWorkflow(string workflowId, object data = null);
11+
Task<string> StartWorkflow(string workflowId, int? version, object data = null);
12+
Task<string> StartWorkflow<TData>(string workflowId, TData data = null) where TData : class;
13+
Task<string> StartWorkflow<TData>(string workflowId, int? version, TData data = null) where TData : class;
14+
15+
Task PublishEvent(string eventName, string eventKey, object eventData, DateTime? effectiveDate = null);
16+
void RegisterWorkflow<TWorkflow>() where TWorkflow : IWorkflow, new();
17+
void RegisterWorkflow<TWorkflow, TData>() where TWorkflow : IWorkflow<TData>, new() where TData : new();
18+
19+
/// <summary>
20+
/// Suspend the execution of a given workflow until .ResumeWorkflow is called
21+
/// </summary>
22+
/// <param name="workflowId"></param>
23+
/// <returns></returns>
24+
Task<bool> SuspendWorkflow(string workflowId);
25+
26+
/// <summary>
27+
/// Resume a previously suspended workflow
28+
/// </summary>
29+
/// <param name="workflowId"></param>
30+
/// <returns></returns>
31+
Task<bool> ResumeWorkflow(string workflowId);
32+
33+
/// <summary>
34+
/// Permanently terminate the exeuction of a given workflow
35+
/// </summary>
36+
/// <param name="workflowId"></param>
37+
/// <returns></returns>
38+
Task<bool> TerminateWorkflow(string workflowId);
39+
40+
}
41+
}

src/WorkflowCore/Interface/IWorkflowHost.cs

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace WorkflowCore.Interface
77
{
8-
public interface IWorkflowHost
8+
public interface IWorkflowHost : IWorkflowController
99
{
1010
/// <summary>
1111
/// Start the workflow host, this enable execution of workflows
@@ -16,36 +16,8 @@ public interface IWorkflowHost
1616
/// Stop the workflow host
1717
/// </summary>
1818
void Stop();
19-
Task<string> StartWorkflow(string workflowId, object data = null);
20-
Task<string> StartWorkflow(string workflowId, int? version, object data = null);
21-
Task<string> StartWorkflow<TData>(string workflowId, TData data = null) where TData : class;
22-
Task<string> StartWorkflow<TData>(string workflowId, int? version, TData data = null) where TData : class;
23-
24-
Task PublishEvent(string eventName, string eventKey, object eventData, DateTime? effectiveDate = null);
25-
void RegisterWorkflow<TWorkflow>() where TWorkflow : IWorkflow, new();
26-
void RegisterWorkflow<TWorkflow, TData>() where TWorkflow : IWorkflow<TData>, new() where TData : new();
27-
28-
/// <summary>
29-
/// Suspend the execution of a given workflow until .ResumeWorkflow is called
30-
/// </summary>
31-
/// <param name="workflowId"></param>
32-
/// <returns></returns>
33-
Task<bool> SuspendWorkflow(string workflowId);
34-
35-
/// <summary>
36-
/// Resume a previously suspended workflow
37-
/// </summary>
38-
/// <param name="workflowId"></param>
39-
/// <returns></returns>
40-
Task<bool> ResumeWorkflow(string workflowId);
41-
42-
/// <summary>
43-
/// Permanently terminate the exeuction of a given workflow
44-
/// </summary>
45-
/// <param name="workflowId"></param>
46-
/// <returns></returns>
47-
Task<bool> TerminateWorkflow(string workflowId);
48-
19+
20+
4921
event StepErrorEventHandler OnStepError;
5022
void ReportStepError(WorkflowInstance workflow, WorkflowStep step, Exception exception);
5123

src/WorkflowCore/ServiceCollectionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public static void AddWorkflow(this IServiceCollection services, Action<Workflow
3232
services.AddTransient<IBackgroundTask, EventConsumer>();
3333
services.AddTransient<IBackgroundTask, RunnablePoller>();
3434

35+
services.AddSingleton<IWorkflowController, WorkflowController>();
3536
services.AddSingleton<IWorkflowHost, WorkflowHost>();
3637
services.AddTransient<IWorkflowExecutor, WorkflowExecutor>();
3738
services.AddTransient<IWorkflowBuilder, WorkflowBuilder>();
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
using System;
2+
using System.Linq;
3+
using System.Reflection;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using Microsoft.Extensions.Logging;
7+
using WorkflowCore.Exceptions;
8+
using WorkflowCore.Interface;
9+
using WorkflowCore.Models;
10+
11+
namespace WorkflowCore.Services
12+
{
13+
public class WorkflowController : IWorkflowController
14+
{
15+
private readonly IPersistenceProvider _persistenceStore;
16+
private readonly IDistributedLockProvider _lockProvider;
17+
private readonly IWorkflowRegistry _registry;
18+
private readonly IQueueProvider _queueProvider;
19+
private readonly ILogger _logger;
20+
21+
22+
public WorkflowController(IPersistenceProvider persistenceStore, IDistributedLockProvider lockProvider, IWorkflowRegistry registry, IQueueProvider queueProvider, ILoggerFactory loggerFactory)
23+
{
24+
_persistenceStore = persistenceStore;
25+
_lockProvider = lockProvider;
26+
_registry = registry;
27+
_queueProvider = queueProvider;
28+
_logger = loggerFactory.CreateLogger<WorkflowController>();
29+
}
30+
31+
public Task<string> StartWorkflow(string workflowId, object data = null)
32+
{
33+
return StartWorkflow(workflowId, null, data);
34+
}
35+
36+
public Task<string> StartWorkflow(string workflowId, int? version, object data = null)
37+
{
38+
return StartWorkflow<object>(workflowId, version, data);
39+
}
40+
41+
public Task<string> StartWorkflow<TData>(string workflowId, TData data = null)
42+
where TData : class
43+
{
44+
return StartWorkflow<TData>(workflowId, null, data);
45+
}
46+
47+
public async Task<string> StartWorkflow<TData>(string workflowId, int? version, TData data = null)
48+
where TData : class
49+
{
50+
51+
var def = _registry.GetDefinition(workflowId, version);
52+
if (def == null)
53+
{
54+
throw new WorkflowNotRegisteredException(workflowId, version);
55+
}
56+
57+
var wf = new WorkflowInstance
58+
{
59+
WorkflowDefinitionId = workflowId,
60+
Version = def.Version,
61+
Data = data,
62+
Description = def.Description,
63+
NextExecution = 0,
64+
CreateTime = DateTime.Now.ToUniversalTime(),
65+
Status = WorkflowStatus.Runnable
66+
};
67+
68+
if ((def.DataType != null) && (data == null))
69+
{
70+
wf.Data = TypeExtensions.GetConstructor(def.DataType, new Type[] { }).Invoke(null);
71+
}
72+
73+
wf.ExecutionPointers.Add(new ExecutionPointer
74+
{
75+
Id = Guid.NewGuid().ToString(),
76+
StepId = 0,
77+
Active = true,
78+
StepName = Enumerable.First<WorkflowStep>(def.Steps, x => x.Id == 0).Name
79+
});
80+
81+
string id = await _persistenceStore.CreateNewWorkflow(wf);
82+
await _queueProvider.QueueWork(id, QueueType.Workflow);
83+
return id;
84+
}
85+
86+
public async Task PublishEvent(string eventName, string eventKey, object eventData, DateTime? effectiveDate = null)
87+
{
88+
_logger.LogDebug("Creating event {0} {1}", eventName, eventKey);
89+
Event evt = new Event();
90+
91+
if (effectiveDate.HasValue)
92+
evt.EventTime = effectiveDate.Value.ToUniversalTime();
93+
else
94+
evt.EventTime = DateTime.Now.ToUniversalTime();
95+
96+
evt.EventData = eventData;
97+
evt.EventKey = eventKey;
98+
evt.EventName = eventName;
99+
evt.IsProcessed = false;
100+
string eventId = await _persistenceStore.CreateEvent(evt);
101+
102+
await _queueProvider.QueueWork(eventId, QueueType.Event);
103+
}
104+
105+
public async Task<bool> SuspendWorkflow(string workflowId)
106+
{
107+
if (!await _lockProvider.AcquireLock(workflowId, new CancellationToken()))
108+
return false;
109+
110+
try
111+
{
112+
var wf = await _persistenceStore.GetWorkflowInstance(workflowId);
113+
if (wf.Status == WorkflowStatus.Runnable)
114+
{
115+
wf.Status = WorkflowStatus.Suspended;
116+
await _persistenceStore.PersistWorkflow(wf);
117+
return true;
118+
}
119+
120+
return false;
121+
}
122+
finally
123+
{
124+
await _lockProvider.ReleaseLock(workflowId);
125+
}
126+
}
127+
128+
public async Task<bool> ResumeWorkflow(string workflowId)
129+
{
130+
if (!await _lockProvider.AcquireLock(workflowId, new CancellationToken()))
131+
{
132+
return false;
133+
}
134+
135+
bool requeue = false;
136+
try
137+
{
138+
var wf = await _persistenceStore.GetWorkflowInstance(workflowId);
139+
if (wf.Status == WorkflowStatus.Suspended)
140+
{
141+
wf.Status = WorkflowStatus.Runnable;
142+
await _persistenceStore.PersistWorkflow(wf);
143+
requeue = true;
144+
return true;
145+
}
146+
147+
return false;
148+
}
149+
finally
150+
{
151+
await _lockProvider.ReleaseLock(workflowId);
152+
if (requeue)
153+
await _queueProvider.QueueWork(workflowId, QueueType.Workflow);
154+
}
155+
156+
return false;
157+
}
158+
159+
public async Task<bool> TerminateWorkflow(string workflowId)
160+
{
161+
if (!await _lockProvider.AcquireLock(workflowId, new CancellationToken()))
162+
{
163+
return false;
164+
}
165+
166+
try
167+
{
168+
var wf = await _persistenceStore.GetWorkflowInstance(workflowId);
169+
wf.Status = WorkflowStatus.Terminated;
170+
await _persistenceStore.PersistWorkflow(wf);
171+
return true;
172+
}
173+
finally
174+
{
175+
await _lockProvider.ReleaseLock(workflowId);
176+
}
177+
}
178+
179+
public void RegisterWorkflow<TWorkflow>()
180+
where TWorkflow : IWorkflow, new()
181+
{
182+
TWorkflow wf = new TWorkflow();
183+
_registry.RegisterWorkflow(wf);
184+
}
185+
186+
public void RegisterWorkflow<TWorkflow, TData>()
187+
where TWorkflow : IWorkflow<TData>, new()
188+
where TData : new()
189+
{
190+
TWorkflow wf = new TWorkflow();
191+
_registry.RegisterWorkflow<TData>(wf);
192+
}
193+
}
194+
}

0 commit comments

Comments
 (0)