Example #1
0
        public CollectionTransitHandler(ISourceRepositoryFactory sourceRepositoryFactory,
                                        IDestinationRepositoryFactory destinationRepositoryFactory,
                                        ICollectionPreparationHandler preparationHandler,
                                        IDocumentsWriterFactory documentsWriterFactory,
                                        IProgressManager manager,
                                        ILogger logger,
                                        CollectionTransitOptions options)
        {
            _manager = manager;
            _logger  = logger;
            _options = options;

            _destination = destinationRepositoryFactory.Create(_logger);
            _source      = sourceRepositoryFactory.Create(_logger);

            _preparationHandler     = preparationHandler;
            _documentsWriterFactory = documentsWriterFactory;
        }
        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));
        }