Beispiel #1
0
        private async Task SendMailAsync(WritableDataContext dbContext, Mail mail, CancellationToken cancellationToken)
        {
            try
            {
                await _smtpClient.SendAsync(mail.Message !, cancellationToken).ConfigureAwait(false);
            }
            catch (InvalidOperationException ex)
            {
                _logger.LogError(ex.InnerException, "Sending MIME message of mail type '{TYPE}' failed. Queue item id: {ID}.", mail.QueueItem.MailType, mail.QueueItem.Id);
                await RegisterItemFailureAsync(dbContext, mail.QueueItem, canRetry : false, cancellationToken).ConfigureAwait(false);

                return;
            }
            catch (CommandException ex)
            {
                _logger.LogError(ex.InnerException, "Sending MIME message of mail type '{TYPE}' failed. Queue item id: {ID}.", mail.QueueItem.MailType, mail.QueueItem.Id);
                await RegisterItemFailureAsync(dbContext, mail.QueueItem, canRetry : true, cancellationToken).ConfigureAwait(false);

                return;
            }

            // cancellation token is not passed since mails should be sent and deleted without interruption,
            // otherwise they could be sent multiple times
            await RemoveItemAsync(dbContext, mail, default).ConfigureAwait(false);
        }
Beispiel #2
0
        private IAsyncEnumerable <MailQueueItem> PeekItems(WritableDataContext dbContext)
        {
            var utcNow = _clock.UtcNow;

            IQueryable <MailQueueItem> queueItems =
                from item in dbContext.MailQueue
                where item.DueDate != null && item.DueDate.Value <= utcNow
                orderby item.DueDate
                select item;

            if (_batchSize > 0)
            {
                queueItems = queueItems.Take(_batchSize);
            }

            return(queueItems.AsAsyncEnumerable());
        }
Beispiel #3
0
        public DbInitializer(WritableDataContext context, IOptions <DbInitializerOptions> options, IClock clock, ILogger <DbInitializer>?logger)
        {
            if (options?.Value == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            _context                 = context ?? throw new ArgumentNullException(nameof(context));
            _clock                   = clock ?? throw new ArgumentNullException(nameof(clock));
            _dbProperties            = _context.GetDbProperties();
            _caseSensitiveComparer   = _dbProperties.CaseSensitiveComparer;
            _caseInsensitiveComparer = _dbProperties.CaseInsensitiveComparer;

            _logger = logger ?? (ILogger)NullLogger.Instance;

            _dbEnsureCreated = options.Value.EnsureCreated;
            _dbSeedObjects   = options.Value.Seed;
        }
        public async Task SeedAsync(WritableDataContext dbContext, CancellationToken cancellationToken = default)
        {
            foreach (var file in _files)
            {
                using (var reader = new StreamReader(file.FilePath))
                    using (var csv = new CsvReader(reader, new CsvConfiguration(s_defaultCsvCulture)))
                    {
                        // applies global configuration
                        _configureReader(csv.Configuration);

                        // applies optional, file level configuration
                        file.ConfigureReader?.Invoke(csv.Configuration);

                        var entities = csv.GetRecords(file.EntityType);

                        dbContext.AddRange(entities);
                    }
            }


            await dbContext.SaveChangesAsync(cancellationToken);
        }
Beispiel #5
0
        private async Task HandleMailErrorAsync(WritableDataContext dbContext, Mail mail, CancellationToken cancellationToken)
        {
            switch (mail.Error)
            {
            case MailTypeNotSupportedException ex:
                _logger.LogError(ex.InnerException, "Mail type '{TYPE}' is not supported. Queue item id: {ID}.", mail.QueueItem.MailType, mail.QueueItem.Id);
                await RegisterItemFailureAsync(dbContext, mail.QueueItem, canRetry : false, cancellationToken).ConfigureAwait(false);

                return;

            case MailModelSerializationException ex:
                _logger.LogError(ex.InnerException, "Model of mail type '{TYPE}' could not be deserialized. Queue item id: {ID}.", mail.QueueItem.MailType, mail.QueueItem.Id);
                await RegisterItemFailureAsync(dbContext, mail.QueueItem, canRetry : false, cancellationToken).ConfigureAwait(false);

                return;

            default:
                _logger.LogError(mail.Error, "Producing MIME message of mail type '{TYPE}' failed. Queue item id: {ID}.", mail.QueueItem.MailType, mail.QueueItem.Id);
                await RegisterItemFailureAsync(dbContext, mail.QueueItem, canRetry : false, cancellationToken).ConfigureAwait(false);

                return;
            }
        }
Beispiel #6
0
        public async Task EnqueueItemAsync(MailModel model, WritableDataContext dbContext, CancellationToken cancellationToken)
        {
            var mailTypeDefinition = _mailTypeCatalog.GetDefinition(model.MailType, throwIfNotFound: true) !;

            var serializedMailModel = mailTypeDefinition.SerializeModel(model);

            var utcNow = _clock.UtcNow;

            dbContext.MailQueue.Add(new MailQueueItem
            {
                CreationDate = utcNow,
                DueDate      = utcNow,
                MailType     = model.MailType,
                MailModel    = serializedMailModel,
            });

            await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);

            if (!dbContext.Database.TryRegisterForPendingTransactionCommit(WakeProcessor))
            {
                WakeProcessor();
            }
        }
Beispiel #7
0
        private async Task SendMailsAsync(IReadOnlyList <Task <Mail> > produceMailTasks, WritableDataContext dbContext, CancellationToken cancellationToken)
        {
            try
            {
                for (int i = 0, n = produceMailTasks.Count; i < n; i++)
                {
                    var mail = await produceMailTasks[i].ConfigureAwait(false);

                    if (mail.Message != null)
                    {
                        if (!_smtpClient.IsConnected)
                        {
                            try
                            {
                                await _smtpClient.ConnectAsync(_smtpHost, _smtpPort, _smtpSecurity, cancellationToken).ConfigureAwait(false);
                            }
                            catch (Exception ex) when(!(ex is OperationCanceledException))
                            {
                                var smtpClient = _smtpClient;

                                _smtpClient = _smtpClientFactory();
                                smtpClient.Dispose();
                                throw;
                            }

                            if (_smtpCredentials != null)
                            {
                                await _smtpClient.AuthenticateAsync(_smtpCredentials, cancellationToken).ConfigureAwait(false);
                            }
                        }

                        await SendMailAsync(dbContext, mail, cancellationToken).ConfigureAwait(false);
                    }
                    else if (mail.Error != null)
                    {
                        await HandleMailErrorAsync(dbContext, mail, cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        // we should never get here
                        throw new InvalidOperationException();
                    }
                }
            }
            finally
            {
                if (_smtpClient.IsConnected)
                {
                    await _smtpClient.DisconnectAsync(quit : true, cancellationToken).ConfigureAwait(false);
                }
            }
        }
Beispiel #8
0
        private async Task RegisterItemFailureAsync(WritableDataContext dbContext, MailQueueItem queueItem, bool canRetry, CancellationToken cancellationToken)
        {
            queueItem.DueDate = canRetry ? GetRetryDueDate(queueItem.CreationDate, queueItem.DueDate !.Value) : (DateTime?)null;

            await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
        }
Beispiel #9
0
        private async Task RemoveItemAsync(WritableDataContext dbContext, Mail mail, CancellationToken cancellationToken)
        {
            dbContext.MailQueue.Remove(mail.QueueItem);

            await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
        }
 public Task SeedAsync(WritableDataContext dbContext, CancellationToken cancellationToken = default) =>
 _seeder(dbContext, cancellationToken);