1
1
using Microsoft . Extensions . Logging ;
2
2
using System ;
3
3
using System . Collections . Generic ;
4
- using System . Text ;
5
4
using System . Threading ;
6
5
using System . Threading . Tasks ;
6
+ using System . Threading . Tasks . Dataflow ;
7
7
using WorkflowCore . Interface ;
8
8
using WorkflowCore . Models ;
9
9
@@ -17,8 +17,7 @@ public abstract class QueueTaskDispatcher : IBackgroundTask
17
17
protected readonly IQueueProvider QueueProvider ;
18
18
protected readonly ILogger Logger ;
19
19
protected readonly WorkflowOptions Options ;
20
- protected Task DispatchTask ;
21
- private SemaphoreSlim _semaphore ;
20
+ protected Task DispatchTask ;
22
21
private CancellationTokenSource _cancellationTokenSource ;
23
22
24
23
protected QueueTaskDispatcher ( IQueueProvider queueProvider , ILoggerFactory loggerFactory , WorkflowOptions options )
@@ -36,7 +35,7 @@ public virtual void Start()
36
35
throw new InvalidOperationException ( ) ;
37
36
38
37
_cancellationTokenSource = new CancellationTokenSource ( ) ;
39
- _semaphore = new SemaphoreSlim ( MaxConcurrentItems ) ;
38
+
40
39
DispatchTask = new Task ( Execute ) ;
41
40
DispatchTask . Start ( ) ;
42
41
}
@@ -45,41 +44,38 @@ public virtual void Stop()
45
44
{
46
45
_cancellationTokenSource . Cancel ( ) ;
47
46
DispatchTask . Wait ( ) ;
48
-
49
- for ( var i = 0 ; i < MaxConcurrentItems ; i ++ )
50
- _semaphore . Wait ( ) ;
51
-
52
47
DispatchTask = null ;
53
48
}
54
49
55
50
private async void Execute ( )
56
51
{
57
52
var cancelToken = _cancellationTokenSource . Token ;
53
+ var opts = new ExecutionDataflowBlockOptions ( )
54
+ {
55
+ MaxDegreeOfParallelism = MaxConcurrentItems ,
56
+ BoundedCapacity = MaxConcurrentItems + 1
57
+ } ;
58
+
59
+ var actionBlock = new ActionBlock < string > ( ExecuteItem , opts ) ;
60
+
58
61
while ( ! cancelToken . IsCancellationRequested )
59
62
{
60
63
try
61
64
{
62
- await _semaphore . WaitAsync ( cancelToken ) ;
63
- string item ;
64
- try
65
- {
66
- item = await QueueProvider . DequeueWork ( Queue , cancelToken ) ;
67
- }
68
- catch
65
+ if ( SpinWait . SpinUntil ( ( ) => actionBlock . InputCount == 0 , Options . IdleTime ) )
69
66
{
70
- _semaphore . Release ( ) ;
71
- throw ;
72
- }
67
+ var item = await QueueProvider . DequeueWork ( Queue , cancelToken ) ;
73
68
74
- if ( item == null )
75
- {
76
- _semaphore . Release ( ) ;
77
- if ( ! QueueProvider . IsDequeueBlocking )
78
- await Task . Delay ( Options . IdleTime , cancelToken ) ;
79
- continue ;
80
- }
69
+ if ( item == null )
70
+ {
71
+ if ( ! QueueProvider . IsDequeueBlocking )
72
+ await Task . Delay ( Options . IdleTime , cancelToken ) ;
73
+ continue ;
74
+ }
81
75
82
- new Task ( ( ) => ExecuteItem ( item , cancelToken ) ) . Start ( ) ;
76
+ if ( ! actionBlock . Post ( item ) )
77
+ await QueueProvider . QueueWork ( item , Queue ) ;
78
+ }
83
79
}
84
80
catch ( OperationCanceledException )
85
81
{
@@ -89,13 +85,15 @@ private async void Execute()
89
85
Logger . LogError ( ex . Message ) ;
90
86
}
91
87
}
88
+ actionBlock . Complete ( ) ;
89
+ await actionBlock . Completion ;
92
90
}
93
91
94
- private async void ExecuteItem ( string itemId , CancellationToken cancellationToken )
92
+ private async Task ExecuteItem ( string itemId )
95
93
{
96
94
try
97
95
{
98
- await ProcessItem ( itemId , cancellationToken ) ;
96
+ await ProcessItem ( itemId , _cancellationTokenSource . Token ) ;
99
97
}
100
98
catch ( OperationCanceledException )
101
99
{
@@ -105,10 +103,6 @@ private async void ExecuteItem(string itemId, CancellationToken cancellationToke
105
103
{
106
104
Logger . LogError ( $ "Error executing item { itemId } - { ex . Message } ") ;
107
105
}
108
- finally
109
- {
110
- _semaphore . Release ( ) ;
111
- }
112
106
}
113
107
}
114
108
}
0 commit comments