public async Task <WorkerResult> RunWorker(ChannelWriter <ReplaceOneModel <BsonDocument> >?failedWrites, ILogger workerLogger, CancellationToken token) { var repository = _repositoryFactory.Create(workerLogger); var totalSuccessful = 0L; var totalFailed = 0L; await foreach (var batch in _batchReader.ReadAllAsync(token)) { try { if (!_dryRun) { await repository.ReplaceManyAsync(batch, token); totalSuccessful += batch.Count; } _notifier.Notify(batch.Count); } catch (OperationCanceledException) { throw; } catch (ReplaceManyException rme) when(rme.Errors.Any()) { // TODO: notify about processed documents besides occurred errors var fails = 0; var retryable = 0; var errSb = new StringBuilder(); foreach (var(index, message) in rme.Errors) { var failedRequest = batch[index]; errSb.AppendLine($"(ID: {failedRequest.Replacement["_id"]}) {message}"); switch (message) { case ErrorUpdateWithMoveToAnotherShard when failedWrites != null: await failedWrites.WriteAsync(failedRequest, token); retryable++; break; default: fails++; break; } } totalFailed += fails; totalSuccessful += rme.ProcessedCount - fails - retryable; workerLogger.Error( "{N:N0} documents failed to transfer, {R:N0} were sent to retry. Total batch: {B:N0}", fails, retryable, batch.Count); workerLogger.Debug("Bulk write exception details:\n{Errors}", errSb.ToString()); } catch (Exception e) { workerLogger.Error(e, "Error occurred while transferring documents"); } finally { token.ThrowIfCancellationRequested(); } } return(new WorkerResult(totalSuccessful, totalFailed)); }