From f981fae83bdc9cca075088ea4c12f617bb942057 Mon Sep 17 00:00:00 2001 From: Jeff Putz Date: Sun, 8 Dec 2024 10:58:57 -0500 Subject: [PATCH 1/2] Fix hosted job intervals #383 --- .../Areas/Forums/BackgroundJobs/CloseAgedTopicsJob.cs | 4 ++-- .../Areas/Forums/BackgroundJobs/PostImageCleanupJob.cs | 4 ++-- .../Areas/Forums/BackgroundJobs/SubscribeNotificationJob.cs | 4 ++-- .../Areas/Forums/BackgroundJobs/UserSessionJob.cs | 4 ++-- src/PopForums.Mvc/PopForums.Mvc.csproj | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/CloseAgedTopicsJob.cs b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/CloseAgedTopicsJob.cs index d9281114..fc80aaa0 100644 --- a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/CloseAgedTopicsJob.cs +++ b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/CloseAgedTopicsJob.cs @@ -5,8 +5,8 @@ namespace PopForums.Mvc.Areas.Forums.BackgroundJobs; public class CloseAgedTopicsJob(IServiceHeartbeatService serviceHeartbeatService, ICloseAgedTopicsWorker closeAgedTopicsWorker) : BackgroundService { - private const int IntervalValue = 43200; - private readonly PeriodicTimer _timer = new(TimeSpan.FromMilliseconds(IntervalValue)); + private const int IntervalValue = 12; + private readonly PeriodicTimer _timer = new(TimeSpan.FromHours(IntervalValue)); protected override async Task ExecuteAsync(CancellationToken stoppingToken) { diff --git a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/PostImageCleanupJob.cs b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/PostImageCleanupJob.cs index e9399dcb..8b706a7e 100644 --- a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/PostImageCleanupJob.cs +++ b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/PostImageCleanupJob.cs @@ -5,8 +5,8 @@ namespace PopForums.Mvc.Areas.Forums.BackgroundJobs; public class PostImageCleanupJob(IServiceHeartbeatService serviceHeartbeatService, IPostImageCleanupWorker postImageCleanupWorker) : BackgroundService { - private const double IntervalValue = 3600; - private readonly PeriodicTimer _timer = new(TimeSpan.FromMilliseconds(IntervalValue)); + private const double IntervalValue = 12; + private readonly PeriodicTimer _timer = new(TimeSpan.FromHours(IntervalValue)); protected override async Task ExecuteAsync(CancellationToken stoppingToken) { diff --git a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/SubscribeNotificationJob.cs b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/SubscribeNotificationJob.cs index 199d8c53..5549c8bf 100644 --- a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/SubscribeNotificationJob.cs +++ b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/SubscribeNotificationJob.cs @@ -5,8 +5,8 @@ namespace PopForums.Mvc.Areas.Forums.BackgroundJobs; public class SubscribeNotificationJob(IServiceHeartbeatService serviceHeartbeatService, ISubscribeNotificationWorker subscribeNotificationWorker) : BackgroundService { - private const double IntervalValue = 3600; - private readonly PeriodicTimer _timer = new(TimeSpan.FromMilliseconds(IntervalValue)); + private const double IntervalValue = 15; + private readonly PeriodicTimer _timer = new(TimeSpan.FromSeconds(IntervalValue)); protected override async Task ExecuteAsync(CancellationToken stoppingToken) { diff --git a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/UserSessionJob.cs b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/UserSessionJob.cs index d5209ceb..02f83310 100644 --- a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/UserSessionJob.cs +++ b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/UserSessionJob.cs @@ -5,8 +5,8 @@ namespace PopForums.Mvc.Areas.Forums.BackgroundJobs; public class UserSessionJob(IServiceHeartbeatService serviceHeartbeatService, IUserSessionWorker userSessionWorker) : BackgroundService { - private const double IntervalValue = 10000; - private readonly PeriodicTimer _timer = new(TimeSpan.FromMilliseconds(IntervalValue)); + private const double IntervalValue = 1; + private readonly PeriodicTimer _timer = new(TimeSpan.FromMinutes(IntervalValue)); protected override async Task ExecuteAsync(CancellationToken stoppingToken) { diff --git a/src/PopForums.Mvc/PopForums.Mvc.csproj b/src/PopForums.Mvc/PopForums.Mvc.csproj index 31140edf..9a1ffd27 100644 --- a/src/PopForums.Mvc/PopForums.Mvc.csproj +++ b/src/PopForums.Mvc/PopForums.Mvc.csproj @@ -2,7 +2,7 @@ PopForums Mvc Class Library - 21.0.0 + 21.0.1 Jeff Putz net9.0 PopForums.Mvc From 5d3e5b6b01864f44634fb845ed46d0df34b94c47 Mon Sep 17 00:00:00 2001 From: Jeff Putz Date: Sun, 8 Dec 2024 17:24:20 -0500 Subject: [PATCH 2/2] Prevent in-process background services from crashing at setup #381 --- .../BackgroundJobs/AwardCalculatorJob.cs | 39 ++++++++++++++---- .../BackgroundJobs/CloseAgedTopicsJob.cs | 21 ++++++++-- .../Areas/Forums/BackgroundJobs/EmailJob.cs | 40 +++++++++++++++---- .../BackgroundJobs/PostImageCleanupJob.cs | 21 ++++++++-- .../Forums/BackgroundJobs/SearchIndexJob.cs | 38 ++++++++++++++---- .../SubscribeNotificationJob.cs | 21 ++++++++-- .../Forums/BackgroundJobs/UserSessionJob.cs | 21 ++++++++-- 7 files changed, 167 insertions(+), 34 deletions(-) diff --git a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/AwardCalculatorJob.cs b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/AwardCalculatorJob.cs index b6c5d8df..53de8b97 100644 --- a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/AwardCalculatorJob.cs +++ b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/AwardCalculatorJob.cs @@ -3,18 +3,43 @@ namespace PopForums.Mvc.Areas.Forums.BackgroundJobs; -public class AwardCalculatorJob(ISettingsManager settingsManager, IServiceHeartbeatService serviceHeartbeatService, IAwardCalculatorWorker awardCalculatorWorker) : BackgroundService +public class AwardCalculatorJob(ISettingsManager settingsManager, IServiceHeartbeatService serviceHeartbeatService, IAwardCalculatorWorker awardCalculatorWorker, IServiceProvider serviceProvider) : BackgroundService { - private readonly PeriodicTimer _timer = new(TimeSpan.FromMilliseconds(settingsManager.Current.ScoringGameCalculatorInterval)); - protected override async Task ExecuteAsync(CancellationToken stoppingToken) { + PeriodicTimer timer; + try + { + timer = new(TimeSpan.FromMilliseconds(settingsManager.Current.ScoringGameCalculatorInterval)); + } + catch(Exception ex) + { + var logger = await GetLogger(); + logger.LogError(ex, $"Error while executing {GetType().FullName} background job. This job will not restart without restarting the app."); + return; + } + while (!stoppingToken.IsCancellationRequested) { - awardCalculatorWorker.Execute(); - await serviceHeartbeatService.RecordHeartbeat(GetType().FullName, Environment.MachineName); - _timer.Period = TimeSpan.FromMilliseconds(settingsManager.Current.ScoringGameCalculatorInterval); - await _timer.WaitForNextTickAsync(stoppingToken); + try + { + awardCalculatorWorker.Execute(); + await serviceHeartbeatService.RecordHeartbeat(GetType().FullName, Environment.MachineName); + timer.Period = TimeSpan.FromMilliseconds(settingsManager.Current.ScoringGameCalculatorInterval); + } + catch (Exception ex) + { + var logger = await GetLogger(); + logger.LogError(ex, $"Error while executing {GetType().FullName} background job."); + } + await timer.WaitForNextTickAsync(stoppingToken); } } + + private async Task> GetLogger() + { + await using var scope = serviceProvider.CreateAsyncScope(); + var logger = scope.ServiceProvider.GetRequiredService>(); + return logger; + } } \ No newline at end of file diff --git a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/CloseAgedTopicsJob.cs b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/CloseAgedTopicsJob.cs index fc80aaa0..f2bbd246 100644 --- a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/CloseAgedTopicsJob.cs +++ b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/CloseAgedTopicsJob.cs @@ -3,7 +3,7 @@ namespace PopForums.Mvc.Areas.Forums.BackgroundJobs; -public class CloseAgedTopicsJob(IServiceHeartbeatService serviceHeartbeatService, ICloseAgedTopicsWorker closeAgedTopicsWorker) : BackgroundService +public class CloseAgedTopicsJob(IServiceHeartbeatService serviceHeartbeatService, ICloseAgedTopicsWorker closeAgedTopicsWorker, IServiceProvider serviceProvider) : BackgroundService { private const int IntervalValue = 12; private readonly PeriodicTimer _timer = new(TimeSpan.FromHours(IntervalValue)); @@ -12,9 +12,24 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { - closeAgedTopicsWorker.Execute(); - await serviceHeartbeatService.RecordHeartbeat(GetType().FullName, Environment.MachineName); + try + { + closeAgedTopicsWorker.Execute(); + await serviceHeartbeatService.RecordHeartbeat(GetType().FullName, Environment.MachineName); + } + catch (Exception ex) + { + var logger = await GetLogger(); + logger.LogError(ex, $"Error while executing {GetType().FullName} background job."); + } await _timer.WaitForNextTickAsync(stoppingToken); } } + + private async Task> GetLogger() + { + await using var scope = serviceProvider.CreateAsyncScope(); + var logger = scope.ServiceProvider.GetRequiredService>(); + return logger; + } } \ No newline at end of file diff --git a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/EmailJob.cs b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/EmailJob.cs index c81375c0..a72781b7 100644 --- a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/EmailJob.cs +++ b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/EmailJob.cs @@ -3,21 +3,45 @@ namespace PopForums.Mvc.Areas.Forums.BackgroundJobs; -public class EmailJob(ISettingsManager settingsManager, IServiceHeartbeatService serviceHeartbeatService, IEmailWorker emailWorker) : BackgroundService +public class EmailJob(ISettingsManager settingsManager, IServiceHeartbeatService serviceHeartbeatService, IEmailWorker emailWorker, IServiceProvider serviceProvider) : BackgroundService { - private readonly PeriodicTimer _timer = new(TimeSpan.FromMilliseconds(settingsManager.Current.MailSendingInverval)); - protected override async Task ExecuteAsync(CancellationToken stoppingToken) { + PeriodicTimer timer; + try + { + timer = new(TimeSpan.FromMilliseconds(settingsManager.Current.MailSendingInverval)); + } + catch(Exception ex) + { + var logger = await GetLogger(); + logger.LogError(ex, $"Error while executing {GetType().FullName} background job. This job will not restart without restarting the app."); + return; + } while (!stoppingToken.IsCancellationRequested) { + try + { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - emailWorker.Execute(); + emailWorker.Execute(); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - await serviceHeartbeatService.RecordHeartbeat(GetType().FullName, Environment.MachineName); - var newTimeSpan = TimeSpan.FromMilliseconds(settingsManager.Current.MailSendingInverval); - _timer.Period = newTimeSpan; - await _timer.WaitForNextTickAsync(stoppingToken); + await serviceHeartbeatService.RecordHeartbeat(GetType().FullName, Environment.MachineName); + var newTimeSpan = TimeSpan.FromMilliseconds(settingsManager.Current.MailSendingInverval); + timer.Period = newTimeSpan; + } + catch (Exception ex) + { + var logger = await GetLogger(); + logger.LogError(ex, $"Error while executing {GetType().FullName} background job."); + } + await timer.WaitForNextTickAsync(stoppingToken); } } + + private async Task> GetLogger() + { + await using var scope = serviceProvider.CreateAsyncScope(); + var logger = scope.ServiceProvider.GetRequiredService>(); + return logger; + } } \ No newline at end of file diff --git a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/PostImageCleanupJob.cs b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/PostImageCleanupJob.cs index 8b706a7e..9435faa3 100644 --- a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/PostImageCleanupJob.cs +++ b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/PostImageCleanupJob.cs @@ -3,7 +3,7 @@ namespace PopForums.Mvc.Areas.Forums.BackgroundJobs; -public class PostImageCleanupJob(IServiceHeartbeatService serviceHeartbeatService, IPostImageCleanupWorker postImageCleanupWorker) : BackgroundService +public class PostImageCleanupJob(IServiceHeartbeatService serviceHeartbeatService, IPostImageCleanupWorker postImageCleanupWorker, IServiceProvider serviceProvider) : BackgroundService { private const double IntervalValue = 12; private readonly PeriodicTimer _timer = new(TimeSpan.FromHours(IntervalValue)); @@ -12,9 +12,24 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { - postImageCleanupWorker.Execute(); - await serviceHeartbeatService.RecordHeartbeat(GetType().FullName, Environment.MachineName); + try + { + postImageCleanupWorker.Execute(); + await serviceHeartbeatService.RecordHeartbeat(GetType().FullName, Environment.MachineName); + } + catch (Exception ex) + { + var logger = await GetLogger(); + logger.LogError(ex, $"Error while executing {GetType().FullName} background job."); + } await _timer.WaitForNextTickAsync(stoppingToken); } } + + private async Task> GetLogger() + { + await using var scope = serviceProvider.CreateAsyncScope(); + var logger = scope.ServiceProvider.GetRequiredService>(); + return logger; + } } \ No newline at end of file diff --git a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/SearchIndexJob.cs b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/SearchIndexJob.cs index b89394ed..b18be8aa 100644 --- a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/SearchIndexJob.cs +++ b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/SearchIndexJob.cs @@ -3,18 +3,42 @@ namespace PopForums.Mvc.Areas.Forums.BackgroundJobs; -public class SearchIndexJob(ISettingsManager settingsManager, IServiceHeartbeatService serviceHeartbeatService, ISearchIndexWorker searchIndexWorker) : BackgroundService +public class SearchIndexJob(ISettingsManager settingsManager, IServiceHeartbeatService serviceHeartbeatService, ISearchIndexWorker searchIndexWorker, IServiceProvider serviceProvider) : BackgroundService { - private readonly PeriodicTimer _timer = new(TimeSpan.FromMilliseconds(settingsManager.Current.SearchIndexingInterval)); - protected override async Task ExecuteAsync(CancellationToken stoppingToken) { + PeriodicTimer timer; + try + { + timer = new(TimeSpan.FromMilliseconds(settingsManager.Current.SearchIndexingInterval)); + } + catch(Exception ex) + { + var logger = await GetLogger(); + logger.LogError(ex, $"Error while executing {GetType().FullName} background job. This job will not restart without restarting the app."); + return; + } while (!stoppingToken.IsCancellationRequested) { - searchIndexWorker.Execute(); - await serviceHeartbeatService.RecordHeartbeat(GetType().FullName, Environment.MachineName); - _timer.Period = TimeSpan.FromMilliseconds(settingsManager.Current.SearchIndexingInterval); - await _timer.WaitForNextTickAsync(stoppingToken); + try + { + searchIndexWorker.Execute(); + await serviceHeartbeatService.RecordHeartbeat(GetType().FullName, Environment.MachineName); + timer.Period = TimeSpan.FromMilliseconds(settingsManager.Current.SearchIndexingInterval); + } + catch (Exception ex) + { + var logger = await GetLogger(); + logger.LogError(ex, $"Error while executing {GetType().FullName} background job."); + } + await timer.WaitForNextTickAsync(stoppingToken); } } + + private async Task> GetLogger() + { + await using var scope = serviceProvider.CreateAsyncScope(); + var logger = scope.ServiceProvider.GetRequiredService>(); + return logger; + } } \ No newline at end of file diff --git a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/SubscribeNotificationJob.cs b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/SubscribeNotificationJob.cs index 5549c8bf..8e86f34a 100644 --- a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/SubscribeNotificationJob.cs +++ b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/SubscribeNotificationJob.cs @@ -3,7 +3,7 @@ namespace PopForums.Mvc.Areas.Forums.BackgroundJobs; -public class SubscribeNotificationJob(IServiceHeartbeatService serviceHeartbeatService, ISubscribeNotificationWorker subscribeNotificationWorker) : BackgroundService +public class SubscribeNotificationJob(IServiceHeartbeatService serviceHeartbeatService, ISubscribeNotificationWorker subscribeNotificationWorker, IServiceProvider serviceProvider) : BackgroundService { private const double IntervalValue = 15; private readonly PeriodicTimer _timer = new(TimeSpan.FromSeconds(IntervalValue)); @@ -12,9 +12,24 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { - subscribeNotificationWorker.Execute(); - await serviceHeartbeatService.RecordHeartbeat(GetType().FullName, Environment.MachineName); + try + { + subscribeNotificationWorker.Execute(); + await serviceHeartbeatService.RecordHeartbeat(GetType().FullName, Environment.MachineName); + } + catch (Exception ex) + { + var logger = await GetLogger(); + logger.LogError(ex, $"Error while executing {GetType().FullName} background job."); + } await _timer.WaitForNextTickAsync(stoppingToken); } } + + private async Task> GetLogger() + { + await using var scope = serviceProvider.CreateAsyncScope(); + var logger = scope.ServiceProvider.GetRequiredService>(); + return logger; + } } \ No newline at end of file diff --git a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/UserSessionJob.cs b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/UserSessionJob.cs index 02f83310..6b5f1b1c 100644 --- a/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/UserSessionJob.cs +++ b/src/PopForums.Mvc/Areas/Forums/BackgroundJobs/UserSessionJob.cs @@ -3,7 +3,7 @@ namespace PopForums.Mvc.Areas.Forums.BackgroundJobs; -public class UserSessionJob(IServiceHeartbeatService serviceHeartbeatService, IUserSessionWorker userSessionWorker) : BackgroundService +public class UserSessionJob(IServiceHeartbeatService serviceHeartbeatService, IUserSessionWorker userSessionWorker, IServiceProvider serviceProvider) : BackgroundService { private const double IntervalValue = 1; private readonly PeriodicTimer _timer = new(TimeSpan.FromMinutes(IntervalValue)); @@ -12,9 +12,24 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { - userSessionWorker.Execute(); - await serviceHeartbeatService.RecordHeartbeat(GetType().FullName, Environment.MachineName); + try + { + userSessionWorker.Execute(); + await serviceHeartbeatService.RecordHeartbeat(GetType().FullName, Environment.MachineName); + } + catch (Exception ex) + { + var logger = await GetLogger(); + logger.LogError(ex, $"Error while executing {GetType().FullName} background job."); + } await _timer.WaitForNextTickAsync(stoppingToken); } } + + private async Task> GetLogger() + { + await using var scope = serviceProvider.CreateAsyncScope(); + var logger = scope.ServiceProvider.GetRequiredService>(); + return logger; + } } \ No newline at end of file