@@ -16,12 +16,13 @@ public class DefaultEventQueue : IEventQueue {
16
16
private readonly IObjectStorage _storage ;
17
17
private readonly IJsonSerializer _serializer ;
18
18
private Timer _queueTimer ;
19
- private bool _processingQueue ;
19
+ private Task _processingQueueTask ;
20
+ private readonly object sync = new object ( ) ;
20
21
private readonly TimeSpan _processQueueInterval = TimeSpan . FromSeconds ( 10 ) ;
21
22
private DateTime ? _suspendProcessingUntil ;
22
23
private DateTime ? _discardQueuedItemsUntil ;
23
24
24
- public DefaultEventQueue ( ExceptionlessConfiguration config , IExceptionlessLog log , ISubmissionClient client , IObjectStorage objectStorage , IJsonSerializer serializer ) : this ( config , log , client , objectStorage , serializer , null , null ) { }
25
+ public DefaultEventQueue ( ExceptionlessConfiguration config , IExceptionlessLog log , ISubmissionClient client , IObjectStorage objectStorage , IJsonSerializer serializer ) : this ( config , log , client , objectStorage , serializer , null , null ) { }
25
26
26
27
public DefaultEventQueue ( ExceptionlessConfiguration config , IExceptionlessLog log , ISubmissionClient client , IObjectStorage objectStorage , IJsonSerializer serializer , TimeSpan ? processQueueInterval , TimeSpan ? queueStartDelay ) {
27
28
_log = log ;
@@ -45,20 +46,30 @@ public void Enqueue(Event ev) {
45
46
}
46
47
47
48
public Task ProcessAsync ( ) {
48
- return Task . Factory . StartNew ( Process ) ;
49
+ return Task . Factory . StartNew (
50
+ ( ) => {
51
+ Process ( ) . ConfigureAwait ( false ) . GetAwaiter ( ) . GetResult ( ) ;
52
+ } ) ;
49
53
}
50
54
51
- public void Process ( ) {
55
+ public Task Process ( ) {
52
56
if ( ! _config . Enabled ) {
53
57
_log . Info ( typeof ( DefaultEventQueue ) , "Configuration is disabled. The queue will not be processed." ) ;
54
- return ;
58
+ return Task . FromResult ( false ) ;
55
59
}
56
60
57
- if ( _processingQueue )
58
- return ;
61
+ TaskCompletionSource < bool > tcs ;
62
+ lock ( sync ) {
63
+ if ( _processingQueueTask != null ) {
64
+ return _processingQueueTask ;
65
+ }
66
+ else {
67
+ tcs = new TaskCompletionSource < bool > ( ) ;
68
+ _processingQueueTask = tcs . Task ;
69
+ }
70
+ }
59
71
60
- _processingQueue = true ;
61
-
72
+ Task resultTask ;
62
73
try {
63
74
_log . Trace ( typeof ( DefaultEventQueue ) , "Processing queue..." ) ;
64
75
_storage . CleanupQueueFiles ( _config . GetQueueName ( ) , _config . QueueMaxAge , _config . QueueMaxAttempts ) ;
@@ -75,43 +86,52 @@ public void Process() {
75
86
var response = _client . PostEvents ( events , _config , _serializer ) ;
76
87
if ( response . Success ) {
77
88
_log . FormattedInfo ( typeof ( DefaultEventQueue ) , "Sent {0} events to \" {1}\" ." , batch . Count , _config . ServerUrl ) ;
78
- } else if ( response . ServiceUnavailable ) {
89
+ }
90
+ else if ( response . ServiceUnavailable ) {
79
91
// You are currently over your rate limit or the servers are under stress.
80
92
_log . Error ( typeof ( DefaultEventQueue ) , "Server returned service unavailable." ) ;
81
93
SuspendProcessing ( ) ;
82
94
deleteBatch = false ;
83
- } else if ( response . PaymentRequired ) {
95
+ }
96
+ else if ( response . PaymentRequired ) {
84
97
// If the organization over the rate limit then discard the event.
85
98
_log . Warn ( typeof ( DefaultEventQueue ) , "Too many events have been submitted, please upgrade your plan." ) ;
86
99
SuspendProcessing ( discardFutureQueuedItems : true , clearQueue : true ) ;
87
- } else if ( response . UnableToAuthenticate ) {
100
+ }
101
+ else if ( response . UnableToAuthenticate ) {
88
102
// The api key was suspended or could not be authorized.
89
103
_log . Error ( typeof ( DefaultEventQueue ) , "Unable to authenticate, please check your configuration. The event will not be submitted." ) ;
90
104
SuspendProcessing ( TimeSpan . FromMinutes ( 15 ) ) ;
91
- } else if ( response . NotFound || response . BadRequest ) {
105
+ }
106
+ else if ( response . NotFound || response . BadRequest ) {
92
107
// The service end point could not be found.
93
108
_log . FormattedError ( typeof ( DefaultEventQueue ) , "Error while trying to submit data: {0}" , response . Message ) ;
94
109
SuspendProcessing ( TimeSpan . FromHours ( 4 ) ) ;
95
- } else if ( response . RequestEntityTooLarge ) {
110
+ }
111
+ else if ( response . RequestEntityTooLarge ) {
96
112
if ( batchSize > 1 ) {
97
113
_log . Error ( typeof ( DefaultEventQueue ) , "Event submission discarded for being too large. The event will be retried with a smaller batch size." ) ;
98
114
batchSize = Math . Max ( 1 , ( int ) Math . Round ( batchSize / 1.5d , 0 ) ) ;
99
115
deleteBatch = false ;
100
- } else {
116
+ }
117
+ else {
101
118
_log . Error ( typeof ( DefaultEventQueue ) , "Event submission discarded for being too large. The event will not be submitted." ) ;
102
119
}
103
- } else if ( ! response . Success ) {
120
+ }
121
+ else if ( ! response . Success ) {
104
122
_log . Error ( typeof ( DefaultEventQueue ) , String . Concat ( "An error occurred while submitting events: " , response . Message ) ) ;
105
123
SuspendProcessing ( ) ;
106
124
deleteBatch = false ;
107
125
}
108
126
109
127
OnEventsPosted ( new EventsPostedEventArgs { Events = events , Response = response } ) ;
110
- } catch ( AggregateException ex ) {
128
+ }
129
+ catch ( AggregateException ex ) {
111
130
_log . Error ( typeof ( DefaultEventQueue ) , ex , String . Concat ( "An error occurred while submitting events: " , ex . Flatten ( ) . Message ) ) ;
112
131
SuspendProcessing ( ) ;
113
132
deleteBatch = false ;
114
- } catch ( Exception ex ) {
133
+ }
134
+ catch ( Exception ex ) {
115
135
_log . Error ( typeof ( DefaultEventQueue ) , ex , String . Concat ( "An error occurred while submitting events: " , ex . Message ) ) ;
116
136
SuspendProcessing ( ) ;
117
137
deleteBatch = false ;
@@ -127,20 +147,26 @@ public void Process() {
127
147
128
148
batch = _storage . GetEventBatch ( _config . GetQueueName ( ) , _serializer , batchSize , maxCreatedDate ) ;
129
149
}
130
- } catch ( Exception ex ) {
150
+ }
151
+ catch ( Exception ex ) {
131
152
_log . Error ( typeof ( DefaultEventQueue ) , ex , String . Concat ( "An error occurred while processing the queue: " , ex . Message ) ) ;
132
153
SuspendProcessing ( ) ;
133
- } finally {
134
- _processingQueue = false ;
135
154
}
155
+ finally {
156
+ tcs . SetResult ( true ) ;
157
+ lock ( sync ) {
158
+ _processingQueueTask = null ;
159
+ resultTask = tcs . Task ;
160
+ }
161
+ }
162
+ return resultTask ;
136
163
}
137
164
138
165
private void OnProcessQueue ( object state ) {
139
166
if ( IsQueueProcessingSuspended )
140
167
return ;
141
-
142
- if ( ! _processingQueue )
143
- Process ( ) ;
168
+
169
+ Process ( ) ;
144
170
}
145
171
146
172
public void SuspendProcessing ( TimeSpan ? duration = null , bool discardFutureQueuedItems = false , bool clearQueue = false ) {
@@ -162,7 +188,8 @@ public void SuspendProcessing(TimeSpan? duration = null, bool discardFutureQueue
162
188
#pragma warning disable 4014
163
189
_storage . CleanupQueueFiles ( _config . GetQueueName ( ) , TimeSpan . Zero ) ;
164
190
#pragma warning restore 4014
165
- } catch ( Exception ) { }
191
+ }
192
+ catch ( Exception ) { }
166
193
}
167
194
168
195
public event EventHandler < EventsPostedEventArgs > EventsPosted ;
@@ -171,7 +198,8 @@ protected virtual void OnEventsPosted(EventsPostedEventArgs e) {
171
198
try {
172
199
if ( EventsPosted != null )
173
200
EventsPosted . Invoke ( this , e ) ;
174
- } catch ( Exception ex ) {
201
+ }
202
+ catch ( Exception ex ) {
175
203
_log . Error ( typeof ( DefaultEventQueue ) , ex , "Error while calling OnEventsPosted event handlers." ) ;
176
204
}
177
205
}
0 commit comments