@@ -21,12 +21,17 @@ internal abstract class QueueConsumer : IBackgroundTask
21
21
protected readonly WorkflowOptions Options ;
22
22
protected Task DispatchTask ;
23
23
private CancellationTokenSource _cancellationTokenSource ;
24
+ private Dictionary < string , EventWaitHandle > _activeTasks ;
25
+ private ConcurrentHashSet < string > _secondPasses ;
24
26
25
27
protected QueueConsumer ( IQueueProvider queueProvider , ILoggerFactory loggerFactory , WorkflowOptions options )
26
28
{
27
29
QueueProvider = queueProvider ;
28
30
Options = options ;
29
31
Logger = loggerFactory . CreateLogger ( GetType ( ) ) ;
32
+
33
+ _activeTasks = new Dictionary < string , EventWaitHandle > ( ) ;
34
+ _secondPasses = new ConcurrentHashSet < string > ( ) ;
30
35
}
31
36
32
37
protected abstract Task ProcessItem ( string itemId , CancellationToken cancellationToken ) ;
@@ -39,9 +44,8 @@ public virtual void Start()
39
44
}
40
45
41
46
_cancellationTokenSource = new CancellationTokenSource ( ) ;
42
-
43
- DispatchTask = new Task ( Execute , TaskCreationOptions . LongRunning ) ;
44
- DispatchTask . Start ( ) ;
47
+
48
+ DispatchTask = Task . Factory . StartNew ( Execute , TaskCreationOptions . LongRunning ) ;
45
49
}
46
50
47
51
public virtual void Stop ( )
@@ -51,20 +55,18 @@ public virtual void Stop()
51
55
DispatchTask = null ;
52
56
}
53
57
54
- private async void Execute ( )
58
+ private async Task Execute ( )
55
59
{
56
- var cancelToken = _cancellationTokenSource . Token ;
57
- var activeTasks = new Dictionary < string , Task > ( ) ;
58
- var secondPasses = new ConcurrentHashSet < string > ( ) ;
60
+ var cancelToken = _cancellationTokenSource . Token ;
59
61
60
62
while ( ! cancelToken . IsCancellationRequested )
61
63
{
62
64
try
63
65
{
64
66
var activeCount = 0 ;
65
- lock ( activeTasks )
67
+ lock ( _activeTasks )
66
68
{
67
- activeCount = activeTasks . Count ;
69
+ activeCount = _activeTasks . Count ;
68
70
}
69
71
if ( activeCount >= MaxConcurrentItems )
70
72
{
@@ -82,45 +84,26 @@ private async void Execute()
82
84
}
83
85
84
86
var hasTask = false ;
85
- lock ( activeTasks )
87
+ lock ( _activeTasks )
86
88
{
87
- hasTask = activeTasks . ContainsKey ( item ) ;
89
+ hasTask = _activeTasks . ContainsKey ( item ) ;
88
90
}
89
91
if ( hasTask )
90
92
{
91
- secondPasses . Add ( item ) ;
93
+ _secondPasses . Add ( item ) ;
92
94
if ( ! EnableSecondPasses )
93
95
await QueueProvider . QueueWork ( item , Queue ) ;
94
96
continue ;
95
97
}
96
98
97
- secondPasses . TryRemove ( item ) ;
99
+ _secondPasses . TryRemove ( item ) ;
98
100
99
- var task = new Task ( async ( object data ) =>
100
- {
101
- try
102
- {
103
- await ExecuteItem ( ( string ) data ) ;
104
- while ( EnableSecondPasses && secondPasses . Contains ( item ) )
105
- {
106
- secondPasses . TryRemove ( item ) ;
107
- await ExecuteItem ( ( string ) data ) ;
108
- }
109
- }
110
- finally
111
- {
112
- lock ( activeTasks )
113
- {
114
- activeTasks . Remove ( ( string ) data ) ;
115
- }
116
- }
117
- } , item ) ;
118
- lock ( activeTasks )
101
+ var waitHandle = new ManualResetEvent ( false ) ;
102
+ lock ( _activeTasks )
119
103
{
120
- activeTasks . Add ( item , task ) ;
104
+ _activeTasks . Add ( item , waitHandle ) ;
121
105
}
122
-
123
- task . Start ( ) ;
106
+ var task = ExecuteItem ( item , waitHandle ) ;
124
107
}
125
108
catch ( OperationCanceledException )
126
109
{
@@ -131,21 +114,26 @@ private async void Execute()
131
114
}
132
115
}
133
116
134
- List < Task > toComplete ;
135
- lock ( activeTasks )
117
+ List < EventWaitHandle > toComplete ;
118
+ lock ( _activeTasks )
136
119
{
137
- toComplete = activeTasks . Values . ToList ( ) ;
120
+ toComplete = _activeTasks . Values . ToList ( ) ;
138
121
}
139
-
140
- foreach ( var task in toComplete )
141
- task . Wait ( ) ;
122
+
123
+ foreach ( var handle in toComplete )
124
+ handle . WaitOne ( ) ;
142
125
}
143
126
144
- private Task ExecuteItem ( string itemId )
127
+ private async Task ExecuteItem ( string itemId , EventWaitHandle waitHandle )
145
128
{
146
129
try
147
130
{
148
- ProcessItem ( itemId , _cancellationTokenSource . Token ) . Wait ( ) ;
131
+ await ProcessItem ( itemId , _cancellationTokenSource . Token ) ;
132
+ while ( EnableSecondPasses && _secondPasses . Contains ( itemId ) )
133
+ {
134
+ _secondPasses . TryRemove ( itemId ) ;
135
+ await ProcessItem ( itemId , _cancellationTokenSource . Token ) ;
136
+ }
149
137
}
150
138
catch ( OperationCanceledException )
151
139
{
@@ -155,8 +143,14 @@ private Task ExecuteItem(string itemId)
155
143
{
156
144
Logger . LogError ( default ( EventId ) , ex , $ "Error executing item { itemId } - { ex . Message } ") ;
157
145
}
158
-
159
- return Task . CompletedTask ;
146
+ finally
147
+ {
148
+ waitHandle . Set ( ) ;
149
+ lock ( _activeTasks )
150
+ {
151
+ _activeTasks . Remove ( itemId ) ;
152
+ }
153
+ }
160
154
}
161
155
}
162
156
}
0 commit comments