private void ProcessItems(Func <IQueueItem <TData>, CancellationToken, Task> handler, bool autoComplete, CancellationToken cancellationToken) { EnsureArg.IsNotNull(handler, nameof(handler)); var linkedCancellationToken = this.CreateLinkedTokenSource(cancellationToken); #pragma warning disable CA2016 // Forward the 'CancellationToken' parameter to methods that take one Task.Run(async() => { this.Logger.LogInformation($"{{LogKey:l}} processing started (queue={this.Options.QueueName}, type={this.GetType().PrettyName()})", args: new[] { LogKeys.Queueing }); while (!linkedCancellationToken.IsCancellationRequested) { IQueueItem <TData> item = null; try { item = await this.DequeueWithIntervalAsync(linkedCancellationToken.Token).AnyContext(); } catch (Exception ex) { this.Logger.LogError(ex, $"{{LogKey:l}} processing error: {ex.Message}", args: new[] { LogKeys.Queueing }); } if (linkedCancellationToken.IsCancellationRequested || item == null) { await Task.Delay(this.Options.ProcessInterval, linkedCancellationToken.Token).AnyContext(); continue; } using (this.Logger.BeginScope(new Dictionary <string, object> { [LogPropertyKeys.CorrelationId] = item.CorrelationId, })) using (var scope = this.Options.Tracer?.BuildSpan($"dequeue {this.Options.QueueName}", LogKeys.Queueing, SpanKind.Consumer, new Span(item.TraceId, item.SpanId)).Activate(this.Logger)) { try { await handler(item, linkedCancellationToken.Token).AnyContext(); if (autoComplete && !item.IsAbandoned && !item.IsCompleted) { await item.CompleteAsync().AnyContext(); } } catch (Exception ex) { Interlocked.Increment(ref this.workerErrorCount); scope.Span.SetStatus(SpanStatus.Failed, ex.GetFullMessage()); this.Logger.LogError(ex, $"{{LogKey:l}} queue processing failed: {ex.GetFullMessage()}", args: new[] { LogKeys.Queueing }); if (!item.IsAbandoned && !item.IsCompleted) { await item.AbandonAsync().AnyContext(); } } } } this.Logger.LogDebug($"{{LogKey:l}} queue processing exiting (name={this.Options.QueueName}, cancellation={linkedCancellationToken.IsCancellationRequested})", LogKeys.Queueing); }, linkedCancellationToken.Token) .ContinueWith(t => linkedCancellationToken.Dispose()); #pragma warning restore CA2016 // Forward the 'CancellationToken' parameter to methods that take one }
private void ProcessItems(Func <IQueueItem <TData>, CancellationToken, Task> handler, bool autoComplete, CancellationToken cancellationToken) { EnsureArg.IsNotNull(handler, nameof(handler)); var linkedCancellationToken = this.CreateLinkedTokenSource(cancellationToken); Task.Run(async() => { this.logger.LogInformation($"{{LogKey:l}} processing started (queue={this.options.Name}, type={this.GetType().PrettyName()})", args: new[] { LogKeys.Queueing }); while (!linkedCancellationToken.IsCancellationRequested) { IQueueItem <TData> item = null; try { item = await this.DequeueWithIntervalAsync(linkedCancellationToken.Token).AnyContext(); } catch (Exception ex) { this.logger.LogError(ex, $"{{LogKey:l}} processing error: {ex.Message}", args: new[] { LogKeys.Queueing }); } if (linkedCancellationToken.IsCancellationRequested || item == null) { continue; } using (this.logger.BeginScope(new Dictionary <string, object> { [LogEventPropertyKeys.CorrelationId] = item.Data.As <IHaveCorrelationId>()?.CorrelationId, })) { try { await handler(item, linkedCancellationToken.Token).AnyContext(); if (autoComplete && !item.IsAbandoned && !item.IsCompleted) { await item.CompleteAsync().AnyContext(); } } catch (Exception ex) { Interlocked.Increment(ref this.workerErrorCount); this.logger.LogError(ex, $"{{LogKey:l}} processing error: {ex.Message}", args: new[] { LogKeys.Queueing }); if (!item.IsAbandoned && !item.IsCompleted) { await item.AbandonAsync().AnyContext(); } } } } this.logger.LogDebug($"queue processing exiting (name={this.options.Name}, cancellation={linkedCancellationToken.IsCancellationRequested})"); }, linkedCancellationToken.Token) .ContinueWith(t => linkedCancellationToken.Dispose()); }