diff --git a/Oqtane.Server/Infrastructure/Jobs/HostedServiceBase.cs b/Oqtane.Server/Infrastructure/Jobs/HostedServiceBase.cs index f3f70ebe..1c9eb377 100644 --- a/Oqtane.Server/Infrastructure/Jobs/HostedServiceBase.cs +++ b/Oqtane.Server/Infrastructure/Jobs/HostedServiceBase.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using Oqtane.Models; using Oqtane.Repository; using Oqtane.Shared; @@ -38,17 +39,23 @@ namespace Oqtane.Infrastructure { await Task.Yield(); // required so that this method does not block startup - try - { - while (!stoppingToken.IsCancellationRequested) + while (!stoppingToken.IsCancellationRequested) + { + using (var scope = _serviceScopeFactory.CreateScope()) { - using (var scope = _serviceScopeFactory.CreateScope()) + ILogger _filelogger = scope.ServiceProvider.GetRequiredService>(); + + try { + var jobs = scope.ServiceProvider.GetRequiredService(); + var jobLogs = scope.ServiceProvider.GetRequiredService(); + var tenantRepository = scope.ServiceProvider.GetRequiredService(); + var tenantManager = scope.ServiceProvider.GetRequiredService(); + // get name of job string jobType = Utilities.GetFullTypeName(GetType().AssemblyQualifiedName); // load jobs and find current job - IJobRepository jobs = scope.ServiceProvider.GetRequiredService(); Job job = jobs.GetJobs().Where(item => item.JobType == jobType).FirstOrDefault(); if (job != null && job.IsEnabled && !job.IsExecuting) { @@ -73,7 +80,9 @@ namespace Oqtane.Infrastructure // determine if the job should be run if (NextExecution <= DateTime.UtcNow && (job.EndDate == null || job.EndDate >= DateTime.UtcNow)) { - IJobLogRepository jobLogs = scope.ServiceProvider.GetRequiredService(); + // update the job to indicate it is running + job.IsExecuting = true; + jobs.UpdateJob(job); // create a job log entry JobLog log = new JobLog(); @@ -84,16 +93,10 @@ namespace Oqtane.Infrastructure log.Notes = ""; log = jobLogs.AddJobLog(log); - // update the job to indicate it is running - job.IsExecuting = true; - jobs.UpdateJob(job); - // execute the job try { var notes = ""; - var tenantRepository = scope.ServiceProvider.GetRequiredService(); - var tenantManager = scope.ServiceProvider.GetRequiredService(); foreach (var tenant in tenantRepository.GetTenants()) { // set tenant and execute job @@ -133,16 +136,19 @@ namespace Oqtane.Infrastructure } } } - - // wait 1 minute - await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken); + catch (Exception ex) + { + // can occur during the initial installation because the database has not yet been created + if (!ex.Message.Contains("No database provider has been configured for this DbContext")) + { + _filelogger.LogError(Utilities.LogMessage(this, $"An Error Occurred Executing Scheduled Job: {Name} - {ex}")); + } + } } - } - catch - { - // can occur during the initial installation as there is no DBContext - } + // wait 1 minute + await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken); + } } private DateTime CalculateNextExecution(DateTime nextExecution, Job job) @@ -191,9 +197,11 @@ namespace Oqtane.Infrastructure public Task StartAsync(CancellationToken cancellationToken) { - try + using (var scope = _serviceScopeFactory.CreateScope()) { - using (var scope = _serviceScopeFactory.CreateScope()) + ILogger _filelogger = scope.ServiceProvider.GetRequiredService>(); + + try { string jobTypeName = Utilities.GetFullTypeName(GetType().AssemblyQualifiedName); IJobRepository jobs = scope.ServiceProvider.GetRequiredService(); @@ -207,7 +215,7 @@ namespace Oqtane.Infrastructure } else { - // auto registration - job will not run on initial installation but will run after restart + // auto registration - job will not run on initial installation due to no DBContext but will run after restart job = new Job { JobType = jobTypeName }; // optional HostedServiceBase properties @@ -233,17 +241,21 @@ namespace Oqtane.Infrastructure jobs.AddJob(job); } } - - _executingTask = ExecuteAsync(_cancellationTokenSource.Token); - - if (_executingTask.IsCompleted) + catch (Exception ex) { - return _executingTask; + // can occur during the initial installation because the database has not yet been created + if (!ex.Message.Contains("No database provider has been configured for this DbContext")) + { + _filelogger.LogError(Utilities.LogMessage(this, $"An Error Occurred Starting Scheduled Job: {Name} - {ex}")); + } } } - catch + + _executingTask = ExecuteAsync(_cancellationTokenSource.Token); + + if (_executingTask.IsCompleted) { - // can occur during the initial installation because this method is called during startup and the database has not yet been created + return _executingTask; } return Task.CompletedTask; @@ -251,9 +263,11 @@ namespace Oqtane.Infrastructure public async Task StopAsync(CancellationToken cancellationToken) { - try + using (var scope = _serviceScopeFactory.CreateScope()) { - using (var scope = _serviceScopeFactory.CreateScope()) + ILogger _filelogger = scope.ServiceProvider.GetRequiredService>(); + + try { string jobTypeName = Utilities.GetFullTypeName(GetType().AssemblyQualifiedName); IJobRepository jobs = scope.ServiceProvider.GetRequiredService(); @@ -266,10 +280,11 @@ namespace Oqtane.Infrastructure jobs.UpdateJob(job); } } - } - catch - { - // error updating the job + catch (Exception ex) + { + // error updating the job + _filelogger.LogError(Utilities.LogMessage(this, $"An Error Occurred Stopping Scheduled Job: {Name} - {ex}")); + } } // stop called without start