public async Task <TimeSpan> RunQuery(string query, IDocumentProcessor processor, DicomReprocessorOptions options) { DateTime start; _logger.Info($"Performing query on {_collNamespace}"); using (IAsyncCursor <BsonDocument> cursor = await MongoQueryParser.GetCursor(_collection, _findOptionsBase, query)) { _logger.Info($"Using MaxDegreeOfParallelism: {_parallelOptions.MaxDegreeOfParallelism}"); _logger.Info($"Batch size is: {(_findOptionsBase.BatchSize.HasValue ? _findOptionsBase.BatchSize.ToString() : "unspecified")}"); _logger.Info($"Sleeping for {options.SleepTime.TotalMilliseconds}ms between batches"); if (!_autoRun) { LogManager.Flush(); Console.Write($"Confirm you want to reprocess documents using the above query in {_collNamespace} [y/N]: "); // Anything other than y/Y cancels the operation string key = Console.ReadLine(); if (key == null || !key.Equals("y", StringComparison.CurrentCultureIgnoreCase)) { _logger.Warn("User cancelled reprocessing by not answering 'y', exiting"); return(default(TimeSpan)); } _logger.Info("User chose to continue with query execution"); } _logger.Info("Starting reprocess operation"); start = DateTime.Now; var totalBatches = 0; //Note: Can only check for the cancellation request every time we start to process a new batch while (await cursor.MoveNextAsync() && !_tokenSource.IsCancellationRequested) { _logger.Debug("Received new batch"); IEnumerable <BsonDocument> batch = cursor.Current; var batchCount = 0; Parallel.ForEach(batch, _parallelOptions, document => { processor.ProcessDocument(document); Interlocked.Increment(ref batchCount); }); _logger.Debug("Batch converted to messages, count was: " + batchCount); processor.SendMessages(); if (++totalBatches % 100 == 0) { processor.LogProgress(); } _logger.Debug($"Batch processed, sleeping for {options.SleepTime.TotalMilliseconds}ms"); Thread.Sleep(options.SleepTime); } } TimeSpan queryTime = DateTime.Now - start; _logger.Info("Reprocessing finished or cancelled, time elapsed: " + queryTime.ToString("g")); return(queryTime); }