7
7
using k8s ;
8
8
using k8s . Models ;
9
9
using KubeOps . Operator . Caching ;
10
+ using KubeOps . Operator . Errors ;
10
11
using KubeOps . Operator . Watcher ;
11
12
using Microsoft . Extensions . Logging ;
12
13
@@ -17,22 +18,20 @@ internal class ResourceEventQueue<TEntity> : IResourceEventQueue<TEntity>
17
18
{
18
19
// TODO: Make configurable
19
20
private const int QueueLimit = 512 ;
20
- private const double MaxRetrySeconds = 64 ;
21
21
22
22
private readonly Channel < ( ResourceEventType type , TEntity resource ) > _queue =
23
23
Channel . CreateBounded < ( ResourceEventType type , TEntity resource ) > ( QueueLimit ) ;
24
24
25
25
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim ( 1 ) ;
26
- private readonly Random _rnd = new Random ( ) ;
27
26
private readonly ILogger < ResourceEventQueue < TEntity > > _logger ;
28
27
private readonly IResourceCache < TEntity > _cache ;
29
28
private readonly IResourceWatcher < TEntity > _watcher ;
30
29
31
30
private readonly IDictionary < string , ResourceTimer < TEntity > > _delayedEnqueue =
32
31
new ConcurrentDictionary < string , ResourceTimer < TEntity > > ( ) ;
33
32
34
- private readonly IDictionary < string , int > _erroredEventsCounter =
35
- new ConcurrentDictionary < string , int > ( ) ;
33
+ private readonly ConcurrentDictionary < string , ExponentialBackoffHandler > _errorHandlers =
34
+ new ConcurrentDictionary < string , ExponentialBackoffHandler > ( ) ;
36
35
37
36
private CancellationTokenSource ? _cancellation ;
38
37
@@ -70,7 +69,13 @@ public async Task Stop()
70
69
timer . Destroy ( ) ;
71
70
}
72
71
72
+ foreach ( var errorBackoff in _errorHandlers . Values )
73
+ {
74
+ errorBackoff . Dispose ( ) ;
75
+ }
76
+
73
77
_delayedEnqueue . Clear ( ) ;
78
+ _errorHandlers . Clear ( ) ;
74
79
}
75
80
76
81
public void Dispose ( )
@@ -93,6 +98,11 @@ public void Dispose()
93
98
{
94
99
ResourceEvent -= ( EventHandler < ( ResourceEventType type , TEntity resource ) > ) handler ;
95
100
}
101
+
102
+ foreach ( var errorBackoff in _errorHandlers . Values )
103
+ {
104
+ errorBackoff . Dispose ( ) ;
105
+ }
96
106
}
97
107
98
108
public async Task Enqueue ( TEntity resource , TimeSpan ? enqueueDelay = null )
@@ -172,40 +182,38 @@ public async Task Enqueue(TEntity resource, TimeSpan? enqueueDelay = null)
172
182
173
183
public void EnqueueErrored ( ResourceEventType type , TEntity resource )
174
184
{
175
- if ( ! _erroredEventsCounter . ContainsKey ( resource . Metadata . Uid ) )
176
- {
177
- _erroredEventsCounter [ resource . Metadata . Uid ] = 0 ;
178
- }
179
- else
180
- {
181
- _erroredEventsCounter [ resource . Metadata . Uid ] ++ ;
182
- }
185
+ var handler = _errorHandlers . GetOrAdd (
186
+ resource . Metadata . Uid ,
187
+ _ =>
188
+ {
189
+ return new ExponentialBackoffHandler (
190
+ async ( ) =>
191
+ {
192
+ _logger . LogTrace (
193
+ @"Backoff (error) requeue timer elapsed for ""{kind}/{name}""." ,
194
+ resource . Kind ,
195
+ resource . Metadata . Name ) ;
196
+ await EnqueueEvent ( type , resource ) ;
197
+ } ) ;
198
+ } ) ;
199
+
183
200
184
- var backoff = ExponentialBackoff ( _erroredEventsCounter [ resource . Metadata . Uid ] ) ;
201
+ var backoff = handler . Retry ( ) ;
185
202
_logger . LogDebug (
186
203
@"Requeue event ""{eventType}"" with backoff ""{backoff}"" for resource ""{kind}/{name}""." ,
187
204
type ,
188
205
backoff ,
189
206
resource . Kind ,
190
207
resource . Metadata . Name ) ;
191
-
192
- var timer = new ResourceTimer < TEntity > (
193
- resource ,
194
- backoff ,
195
- async delayedResource =>
196
- {
197
- _logger . LogTrace (
198
- @"Backoff (error) requeue timer elapsed for ""{kind}/{name}""." ,
199
- delayedResource . Kind ,
200
- delayedResource . Metadata . Name ) ;
201
- _delayedEnqueue . Remove ( delayedResource . Metadata . Uid ) ;
202
- await EnqueueEvent ( type , delayedResource ) ;
203
- } ) ;
204
- _delayedEnqueue . Add ( resource . Metadata . Uid , timer ) ;
205
- timer . Start ( ) ;
206
208
}
207
209
208
- public void ClearError ( TEntity resource ) => _erroredEventsCounter . Remove ( resource . Metadata . Uid ) ;
210
+ public void ClearError ( TEntity resource )
211
+ {
212
+ if ( _errorHandlers . Remove ( resource . Metadata . Uid , out var handler ) )
213
+ {
214
+ handler . Dispose ( ) ;
215
+ }
216
+ }
209
217
210
218
private async void OnWatcherEvent ( object ? _ , ( WatchEventType type , TEntity resource ) args )
211
219
{
@@ -292,9 +300,5 @@ await _queue.Reader.WaitToReadAsync(_cancellation.Token))
292
300
ResourceEvent ? . Invoke ( this , message ) ;
293
301
}
294
302
}
295
-
296
- private TimeSpan ExponentialBackoff ( int retryCount ) => TimeSpan
297
- . FromSeconds ( Math . Min ( Math . Pow ( 2 , retryCount ) , MaxRetrySeconds ) )
298
- . Add ( TimeSpan . FromMilliseconds ( _rnd . Next ( 0 , 1000 ) ) ) ;
299
303
}
300
304
}
0 commit comments