public ScheduledNotificationsJob( SchedulesCache schedulesCache, IApplicationRepositoryFactory repoFactory, NotificationsQueue notificationsQueue, ILogger <ScheduledNotificationsJob> logger, ApplicationBehaviorHelper helper) { _schedulesCache = schedulesCache; _repoFactory = repoFactory; _notificationsQueue = notificationsQueue; _logger = logger; _helper = helper; }
private int PollingBatchSize => _options.PendingNotificationExpiryInSeconds * 2; // Assuming 2 SMS per second protected override async Task ExecuteAsync(CancellationToken cancellation) { _logger.LogInformation(GetType().Name + " Started."); while (!cancellation.IsCancellationRequested) { // Grab a hold of a concrete list of adopted tenantIds at the current moment var tenantIds = _instanceInfo.AdoptedTenantIds; if (tenantIds.Any()) { // Match every tenantID to the Task of polling // Wait until all adopted tenants have returned await Task.WhenAll(tenantIds.Select(async tenantId => { try // To make sure the background service keeps running { // Begin serializable transaction using var trx = TransactionFactory.Serializable(TransactionScopeOption.RequiresNew); // Retrieve NEW or stale PENDING SMS messages, after marking them as fresh PENDING var repo = _repoFactory.GetRepository(tenantId); IEnumerable <MessageForSave> smsesReady = await repo.Notifications_Messages__Poll( _options.PendingNotificationExpiryInSeconds, PollingBatchSize, cancellation); // Queue the SMS messages for dispatching foreach (SmsToSend sms in smsesReady.Select(e => NotificationsQueue.FromEntity(e, tenantId))) { _queue.QueueBackgroundWorkItem(sms); } trx.Complete(); // Log a warning, since in theory this job should rarely find anything, if it finds stuff too often it means something is wrong if (smsesReady.Any()) { _logger.LogWarning($"{nameof(SmsPollingJob)} found {smsesReady.Count()} SMSes in database for tenant {tenantId}."); } } catch (TaskCanceledException) { } catch (OperationCanceledException) { } catch (Exception ex) { _logger.LogError(ex, $"Error in {GetType().Name}."); } })); } // Go to sleep until the next round await Task.Delay(_options.NotificationCheckFrequencyInSeconds * 1000, cancellation); } }