1717 using ServiceControl . Infrastructure . Metrics ;
1818 using Transports ;
1919
20- class AuditIngestion : IHostedService
20+ class AuditIngestion : BackgroundService
2121 {
2222 static readonly long FrequencyInMilliseconds = Stopwatch . Frequency / 1000 ;
2323
@@ -59,23 +59,15 @@ public AuditIngestion(
5959
6060 errorHandlingPolicy = new AuditIngestionFaultPolicy ( failedImportsStorage , settings . LoggingSettings , OnCriticalError ) ;
6161
62- watchdog = new Watchdog ( "audit message ingestion" , EnsureStarted , EnsureStopped , ingestionState . ReportError , ingestionState . Clear , settings . TimeToRestartAuditIngestionAfterFailure , logger ) ;
63-
64- ingestionWorker = Task . Run ( ( ) => Loop ( ) , CancellationToken . None ) ;
65- }
66-
67- public Task StartAsync ( CancellationToken _ ) => watchdog . Start ( ( ) => applicationLifetime . StopApplication ( ) ) ;
68-
69- public async Task StopAsync ( CancellationToken cancellationToken )
70- {
71- await watchdog . Stop ( ) ;
72- channel . Writer . Complete ( ) ;
73- await ingestionWorker ;
74-
75- if ( transportInfrastructure != null )
76- {
77- await transportInfrastructure . Shutdown ( cancellationToken ) ;
78- }
62+ watchdog = new Watchdog (
63+ "audit message ingestion" ,
64+ EnsureStarted ,
65+ EnsureStopped ,
66+ ingestionState . ReportError ,
67+ ingestionState . Clear ,
68+ settings . TimeToRestartAuditIngestionAfterFailure ,
69+ logger
70+ ) ;
7971 }
8072
8173 Task OnCriticalError ( string failure , Exception exception )
@@ -139,7 +131,7 @@ async Task EnsureStarted(CancellationToken cancellationToken = default)
139131 }
140132 catch ( OperationCanceledException e ) when ( e . CancellationToken == cancellationToken )
141133 {
142- // ignored
134+ logger . Info ( "StopReceive cancelled" ) ;
143135 }
144136 }
145137
@@ -176,7 +168,7 @@ async Task EnsureStopped(CancellationToken cancellationToken = default)
176168 }
177169 catch ( OperationCanceledException e ) when ( e . CancellationToken == cancellationToken )
178170 {
179- // ignored
171+ logger . Info ( "StopReceive cancelled" ) ;
180172 }
181173 finally
182174 {
@@ -202,51 +194,86 @@ async Task OnMessage(MessageContext messageContext, CancellationToken cancellati
202194 await taskCompletionSource . Task ;
203195 }
204196
205- async Task Loop ( )
197+ public override async Task StartAsync ( CancellationToken cancellationToken )
206198 {
207- var contexts = new List < MessageContext > ( transportSettings . MaxConcurrency . Value ) ;
199+ await watchdog . Start ( ( ) => applicationLifetime . StopApplication ( ) ) ;
200+ await base . StartAsync ( cancellationToken ) ;
201+ }
208202
209- while ( await channel . Reader . WaitToReadAsync ( ) )
203+ protected override async Task ExecuteAsync ( CancellationToken stoppingToken )
204+ {
205+ try
210206 {
211- // will only enter here if there is something to read.
212- try
207+ var contexts = new List < MessageContext > ( transportSettings . MaxConcurrency . Value ) ;
208+
209+ while ( await channel . Reader . WaitToReadAsync ( stoppingToken ) )
213210 {
214- // as long as there is something to read this will fetch up to MaximumConcurrency items
215- while ( channel . Reader . TryRead ( out var context ) )
211+ // will only enter here if there is something to read.
212+ try
216213 {
217- contexts . Add ( context ) ;
214+ // as long as there is something to read this will fetch up to MaximumConcurrency items
215+ while ( channel . Reader . TryRead ( out var context ) )
216+ {
217+ contexts . Add ( context ) ;
218+ }
219+
220+ batchSizeMeter . Mark ( contexts . Count ) ;
221+ using ( batchDurationMeter . Measure ( ) )
222+ {
223+ await auditIngestor . Ingest ( contexts ) ;
224+ }
218225 }
226+ catch ( Exception e )
227+ {
228+ // signal all message handling tasks to terminate
229+ foreach ( var context in contexts )
230+ {
231+ _ = context . GetTaskCompletionSource ( ) . TrySetException ( e ) ;
232+ }
233+
234+ if ( e is OperationCanceledException && stoppingToken . IsCancellationRequested )
235+ {
236+ logger . Info ( "Batch cancelled" , e ) ;
237+ break ;
238+ }
219239
220- batchSizeMeter . Mark ( contexts . Count ) ;
221- using ( batchDurationMeter . Measure ( ) )
240+ logger . Info ( "Ingesting messages failed" , e ) ;
241+ }
242+ finally
222243 {
223- await auditIngestor . Ingest ( contexts ) ;
244+ contexts . Clear ( ) ;
224245 }
225246 }
226- catch ( OperationCanceledException )
227- {
228- //Do nothing as we are shutting down
229- continue ;
230- }
231- catch ( Exception e ) // show must go on
247+ // will fall out here when writer is completed
248+ }
249+ catch ( OperationCanceledException ) when ( stoppingToken . IsCancellationRequested )
250+ {
251+ // ExecuteAsync cancelled
252+ }
253+ }
254+
255+ public override async Task StopAsync ( CancellationToken cancellationToken )
256+ {
257+ try
258+ {
259+ await watchdog . Stop ( ) ;
260+ channel . Writer . Complete ( ) ;
261+ await base . StopAsync ( cancellationToken ) ;
262+ }
263+ finally
264+ {
265+ if ( transportInfrastructure != null )
232266 {
233- if ( logger . IsInfoEnabled )
267+ try
234268 {
235- logger . Info ( "Ingesting messages failed" , e ) ;
269+ await transportInfrastructure . Shutdown ( cancellationToken ) ;
236270 }
237-
238- // signal all message handling tasks to terminate
239- foreach ( var context in contexts )
271+ catch ( OperationCanceledException e ) when ( cancellationToken . IsCancellationRequested )
240272 {
241- context . GetTaskCompletionSource ( ) . TrySetException ( e ) ;
273+ logger . Info ( "Shutdown cancelled" , e ) ;
242274 }
243275 }
244- finally
245- {
246- contexts . Clear ( ) ;
247- }
248276 }
249- // will fall out here when writer is completed
250277 }
251278
252279 TransportInfrastructure transportInfrastructure ;
@@ -265,7 +292,6 @@ async Task Loop()
265292 readonly Meter batchDurationMeter ;
266293 readonly Counter receivedMeter ;
267294 readonly Watchdog watchdog ;
268- readonly Task ingestionWorker ;
269295 readonly IHostApplicationLifetime applicationLifetime ;
270296
271297 static readonly ILog logger = LogManager . GetLogger < AuditIngestion > ( ) ;
0 commit comments