diff --git a/src/Business/Grand.Business.Core/Interfaces/System/ScheduleTasks/IScheduleTaskService.cs b/src/Business/Grand.Business.Core/Interfaces/System/ScheduleTasks/IScheduleTaskService.cs index eec3f4906..89f7d02d9 100644 --- a/src/Business/Grand.Business.Core/Interfaces/System/ScheduleTasks/IScheduleTaskService.cs +++ b/src/Business/Grand.Business.Core/Interfaces/System/ScheduleTasks/IScheduleTaskService.cs @@ -14,9 +14,9 @@ public interface IScheduleTaskService /// /// Gets a task by its type /// - /// Task type + /// Task name /// Task - Task GetTaskByType(string type); + Task GetTaskByName(string name); /// /// Gets all tasks diff --git a/src/Core/Grand.Domain/Tasks/ScheduleTask.cs b/src/Core/Grand.Domain/Tasks/ScheduleTask.cs index ae6ea19c5..d19979140 100644 --- a/src/Core/Grand.Domain/Tasks/ScheduleTask.cs +++ b/src/Core/Grand.Domain/Tasks/ScheduleTask.cs @@ -2,8 +2,7 @@ public class ScheduleTask : BaseEntity { - public string ScheduleTaskName { get; set; } - public string Type { get; set; } + public string ScheduleTaskName { get; set; } public bool Enabled { get; set; } public bool StopOnError { get; set; } public DateTime? LastStartUtc { get; set; } diff --git a/src/Modules/Grand.Module.Installer/Services/InstallDataScheduleTasks.cs b/src/Modules/Grand.Module.Installer/Services/InstallDataScheduleTasks.cs index 7ba599f91..c5ec64e53 100644 --- a/src/Modules/Grand.Module.Installer/Services/InstallDataScheduleTasks.cs +++ b/src/Modules/Grand.Module.Installer/Services/InstallDataScheduleTasks.cs @@ -12,56 +12,42 @@ protected virtual Task InstallScheduleTasks() var tasks = new List { new() { ScheduleTaskName = "Send emails", - Type = - "Grand.Module.ScheduledTasks.BackgroundServices.QueuedMessagesSendScheduleTask, Grand.Module.ScheduledTasks", Enabled = true, StopOnError = false, TimeInterval = 1 }, new() { ScheduleTaskName = "Delete guests", - Type = - "Grand.Module.ScheduledTasks.BackgroundServices.DeleteGuestsScheduleTask, Grand.Module.ScheduledTasks", Enabled = true, StopOnError = false, TimeInterval = 1440 }, new() { ScheduleTaskName = "Clear cache", - Type = - "Grand.Module.ScheduledTasks.BackgroundServices.ClearCacheScheduleTask, Grand.Module.ScheduledTasks", Enabled = false, StopOnError = false, TimeInterval = 120 }, new() { ScheduleTaskName = "Update currency exchange rates", - Type = - "Grand.Module.ScheduledTasks.BackgroundServices.UpdateExchangeRateScheduleTask, Grand.Module.ScheduledTasks", Enabled = true, StopOnError = false, TimeInterval = 1440 }, new() { ScheduleTaskName = "Generate sitemap XML file", - Type = - "Grand.Module.ScheduledTasks.BackgroundServices.GenerateSitemapXmlTask, Grand.Module.ScheduledTasks", Enabled = false, StopOnError = false, TimeInterval = 10080 }, new() { ScheduleTaskName = "End of the auctions", - Type = - "Grand.Module.ScheduledTasks.BackgroundServices.EndAuctionsTask, Grand.Module.ScheduledTasks", Enabled = false, StopOnError = false, TimeInterval = 60 }, new() { ScheduleTaskName = "Cancel unpaid and pending orders", - Type = - "Grand.Module.ScheduledTasks.BackgroundServices.CancelOrderScheduledTask, Grand.Module.ScheduledTasks", Enabled = false, StopOnError = false, TimeInterval = 1440 diff --git a/src/Modules/Grand.Module.ScheduledTasks/BackgroundServices/ScheduleTaskService.cs b/src/Modules/Grand.Module.ScheduledTasks/BackgroundServices/ScheduleTaskService.cs index 15df5588d..c17036276 100644 --- a/src/Modules/Grand.Module.ScheduledTasks/BackgroundServices/ScheduleTaskService.cs +++ b/src/Modules/Grand.Module.ScheduledTasks/BackgroundServices/ScheduleTaskService.cs @@ -35,17 +35,16 @@ public virtual Task GetTaskById(string taskId) } /// - /// Gets a task by its type + /// Gets a task by its name /// - /// Task type /// Task - public virtual async Task GetTaskByType(string type) + public virtual async Task GetTaskByName(string name) { - if (string.IsNullOrWhiteSpace(type)) + if (string.IsNullOrWhiteSpace(name)) return null; - var query = _taskRepository.Table.Where(st => st.Type == type).OrderByDescending(t => t.Id); - return await Task.FromResult(query.FirstOrDefault()); + var task = _taskRepository.Table.FirstOrDefault(x => x.ScheduleTaskName == name); + return await Task.FromResult(task); } /// diff --git a/src/Modules/Grand.Module.ScheduledTasks/Grand.Module.ScheduledTasks.csproj b/src/Modules/Grand.Module.ScheduledTasks/Grand.Module.ScheduledTasks.csproj index 31419e35d..33725b7d6 100644 --- a/src/Modules/Grand.Module.ScheduledTasks/Grand.Module.ScheduledTasks.csproj +++ b/src/Modules/Grand.Module.ScheduledTasks/Grand.Module.ScheduledTasks.csproj @@ -23,11 +23,11 @@ - ..\..\Web\Grand.Web\Modules\Grand.Module.ScheduledTask\ + ..\..\Web\Grand.Web\Modules\Grand.Module.ScheduledTasks\ $(OutputPath) - ..\..\Web\Grand.Web\Modules\Grand.Module.ScheduledTask\ + ..\..\Web\Grand.Web\Modules\Grand.Module.ScheduledTasks\ $(OutputPath) diff --git a/src/Modules/Grand.Module.ScheduledTasks/Startup/StartupApplication.cs b/src/Modules/Grand.Module.ScheduledTasks/Startup/StartupApplication.cs index f1b3b3d11..cd0191149 100644 --- a/src/Modules/Grand.Module.ScheduledTasks/Startup/StartupApplication.cs +++ b/src/Modules/Grand.Module.ScheduledTasks/Startup/StartupApplication.cs @@ -26,12 +26,12 @@ private void RegisterTask(IServiceCollection serviceCollection) { serviceCollection.AddScoped(); - serviceCollection.AddScoped(); - serviceCollection.AddScoped(); - serviceCollection.AddScoped(); - serviceCollection.AddScoped(); - serviceCollection.AddScoped(); - serviceCollection.AddScoped(); - serviceCollection.AddScoped(); + serviceCollection.AddKeyedScoped("Send emails"); + serviceCollection.AddKeyedScoped("Clear cache"); + serviceCollection.AddKeyedScoped("Generate sitemap XML file"); + serviceCollection.AddKeyedScoped("Delete guests"); + serviceCollection.AddKeyedScoped("Update currency exchange rates"); + serviceCollection.AddKeyedScoped("End of the auctions"); + serviceCollection.AddKeyedScoped("Cancel unpaid and pending orders"); } } \ No newline at end of file diff --git a/src/Web/Grand.Web.Admin/Areas/Admin/Views/ScheduleTask/EditScheduler.cshtml b/src/Web/Grand.Web.Admin/Areas/Admin/Views/ScheduleTask/EditScheduler.cshtml index 324e0731a..d343197b8 100644 --- a/src/Web/Grand.Web.Admin/Areas/Admin/Views/ScheduleTask/EditScheduler.cshtml +++ b/src/Web/Grand.Web.Admin/Areas/Admin/Views/ScheduleTask/EditScheduler.cshtml @@ -43,14 +43,7 @@
- - -
- -
- -
-
+
diff --git a/src/Web/Grand.Web.Admin/Controllers/ScheduleTaskController.cs b/src/Web/Grand.Web.Admin/Controllers/ScheduleTaskController.cs index 53e38fcbd..a9164e9e4 100644 --- a/src/Web/Grand.Web.Admin/Controllers/ScheduleTaskController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/ScheduleTaskController.cs @@ -117,8 +117,7 @@ public async Task EditScheduler(ScheduleTaskModel model, bool con return RedirectToAction("List"); } - model.ScheduleTaskName = scheduleTask.ScheduleTaskName; - model.Type = scheduleTask.Type; + model.ScheduleTaskName = scheduleTask.ScheduleTaskName; model = await PrepareStores(model); Error(ModelState); @@ -132,9 +131,8 @@ public async Task RunNow(string id) { var scheduleTask = await _scheduleTaskService.GetTaskById(id); if (scheduleTask == null) throw new Exception("Schedule task cannot be loaded"); - var typeofTask = Type.GetType(scheduleTask.Type); - var task = HttpContext.RequestServices.GetServices() - .FirstOrDefault(x => x.GetType() == typeofTask); + + var task = HttpContext.RequestServices.GetRequiredKeyedService(scheduleTask.ScheduleTaskName); if (task != null) { scheduleTask.LastStartUtc = DateTime.UtcNow; @@ -157,7 +155,7 @@ public async Task RunNow(string id) } else { - Error($"Task {typeofTask?.Name} has not been registered"); + Error($"Task {scheduleTask.ScheduleTaskName} has not been registered"); } } catch (Exception exc) diff --git a/src/Web/Grand.Web.Admin/Mapper/ScheduleTaskProfile.cs b/src/Web/Grand.Web.Admin/Mapper/ScheduleTaskProfile.cs index ffdce8708..cc296e8b4 100644 --- a/src/Web/Grand.Web.Admin/Mapper/ScheduleTaskProfile.cs +++ b/src/Web/Grand.Web.Admin/Mapper/ScheduleTaskProfile.cs @@ -14,7 +14,6 @@ public ScheduleTaskProfile() CreateMap() .ForMember(dest => dest.Id, mo => mo.Ignore()) - .ForMember(dest => dest.Type, mo => mo.Ignore()) .ForMember(dest => dest.ScheduleTaskName, mo => mo.Ignore()) .ForMember(dest => dest.LastNonSuccessEndUtc, mo => mo.Ignore()) .ForMember(dest => dest.LastStartUtc, mo => mo.Ignore()) diff --git a/src/Web/Grand.Web.Admin/Models/Tasks/ScheduleTaskModel.cs b/src/Web/Grand.Web.Admin/Models/Tasks/ScheduleTaskModel.cs index db153ca1f..b4c44c4e4 100644 --- a/src/Web/Grand.Web.Admin/Models/Tasks/ScheduleTaskModel.cs +++ b/src/Web/Grand.Web.Admin/Models/Tasks/ScheduleTaskModel.cs @@ -10,10 +10,7 @@ public class ScheduleTaskModel : BaseEntityModel public string ScheduleTaskName { get; set; } [GrandResourceDisplayName("Admin.System.ScheduleTasks.LeasedByMachineName")] - public string LeasedByMachineName { get; set; } - - [GrandResourceDisplayName("Admin.System.ScheduleTasks.Type")] - public string Type { get; set; } + public string LeasedByMachineName { get; set; } [GrandResourceDisplayName("Admin.System.ScheduleTasks.Enabled")] public bool Enabled { get; set; } diff --git a/src/Web/Grand.Web.Common/Extensions/KeyedServiceHelper.cs b/src/Web/Grand.Web.Common/Extensions/KeyedServiceHelper.cs new file mode 100644 index 000000000..678e9bc2d --- /dev/null +++ b/src/Web/Grand.Web.Common/Extensions/KeyedServiceHelper.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Grand.Web.Common.Extensions; + +public static class KeyedServiceHelper +{ + public static IList GetKeyedServicesForInterface(IServiceCollection services) + { + var keyedServices = new List(); + foreach (var service in services) + { + if (service.ServiceType == typeof(TInterface) && service.IsKeyedService) + { + keyedServices.Add(service.ServiceKey.ToString()); + } + } + return keyedServices; + } +} \ No newline at end of file diff --git a/src/Web/Grand.Web.Common/Infrastructure/BackgroundServiceTask.cs b/src/Web/Grand.Web.Common/Infrastructure/BackgroundServiceTask.cs index 7c87adc98..01517ebca 100644 --- a/src/Web/Grand.Web.Common/Infrastructure/BackgroundServiceTask.cs +++ b/src/Web/Grand.Web.Common/Infrastructure/BackgroundServiceTask.cs @@ -10,11 +10,11 @@ namespace Grand.Web.Common.Infrastructure; public class BackgroundServiceTask : BackgroundService { private readonly IServiceProvider _serviceProvider; - private readonly string _taskType; + private readonly string Name; - public BackgroundServiceTask(string taskType, IServiceProvider serviceProvider) + public BackgroundServiceTask(string name, IServiceProvider serviceProvider) { - _taskType = taskType; + Name = name; _serviceProvider = serviceProvider; } @@ -27,10 +27,10 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) var serviceProvider = scope.ServiceProvider; var logger = serviceProvider.GetService>(); var scheduleTaskService = serviceProvider.GetService(); - var task = await scheduleTaskService.GetTaskByType(_taskType); + var task = await scheduleTaskService.GetTaskByName(Name); if (task == null) { - logger.LogInformation("Task {TaskType} is not exists in the database", _taskType); + logger.LogInformation("Task {TaskName} is not exists in the database", Name); break; } @@ -39,66 +39,55 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) if (task.Enabled && (string.IsNullOrEmpty(task.LeasedByMachineName) || machineName == task.LeasedByMachineName)) { - var typeofTask = Type.GetType(_taskType); - if (typeofTask != null) + + var scheduleTask = serviceProvider.GetRequiredKeyedService(task.ScheduleTaskName); + if (scheduleTask != null) { - var scheduleTask = serviceProvider.GetServices() - .FirstOrDefault(x => x.GetType() == typeofTask); - if (scheduleTask != null) + //assign current customer (background task) / current store (from task) + await WorkContext(serviceProvider, task); + var runTask = true; + if (task.LastStartUtc.HasValue) { - //assign current customer (background task) / current store (from task) - await WorkContext(serviceProvider, task); - var runTask = true; - if (task.LastStartUtc.HasValue) + var dateTimeNow = DateTime.UtcNow; + if (dateTimeNow < task.LastStartUtc.Value.AddMinutes(task.TimeInterval)) { - var dateTimeNow = DateTime.UtcNow; - if (dateTimeNow < task.LastStartUtc.Value.AddMinutes(task.TimeInterval)) - { - runTask = false; - timeInterval = - (int)(task.LastStartUtc.Value.AddMinutes(task.TimeInterval) - dateTimeNow) - .TotalMinutes; - } - else - { - runTask = true; - timeInterval = task.TimeInterval > 0 ? task.TimeInterval : 1; - } + runTask = false; + timeInterval = + (int)(task.LastStartUtc.Value.AddMinutes(task.TimeInterval) - dateTimeNow) + .TotalMinutes; } - - if (runTask) + else { - task.LastStartUtc = DateTime.UtcNow; - try - { - //TODO - add settings - //logger.Information($"Task {_taskType} execute"); - await scheduleTask.Execute(); - task.LastSuccessUtc = DateTime.UtcNow; - task.LastNonSuccessEndUtc = null; - } - catch (Exception exc) - { - task.LastNonSuccessEndUtc = DateTime.UtcNow; - task.Enabled = !task.StopOnError; - logger.LogError(exc, - "Error while running the \'{TaskScheduleTaskName}\' schedule task", - task.ScheduleTaskName); - } + runTask = true; + timeInterval = task.TimeInterval > 0 ? task.TimeInterval : 1; } } - else + + if (runTask) { - task.Enabled = !task.StopOnError; - task.LastNonSuccessEndUtc = DateTime.UtcNow; - logger.LogError("Type {TaskType} is not registered", _taskType); + task.LastStartUtc = DateTime.UtcNow; + try + { + logger.LogInformation($"Task {Name} execute"); + await scheduleTask.Execute(); + task.LastSuccessUtc = DateTime.UtcNow; + task.LastNonSuccessEndUtc = null; + } + catch (Exception exc) + { + task.LastNonSuccessEndUtc = DateTime.UtcNow; + task.Enabled = !task.StopOnError; + logger.LogError(exc, + "Error while running the \'{TaskScheduleTaskName}\' schedule task", + task.ScheduleTaskName); + } } } else { task.Enabled = !task.StopOnError; task.LastNonSuccessEndUtc = DateTime.UtcNow; - logger.LogError("Type {TaskType} is null (type not exists)", _taskType); + logger.LogError("Type {TaskName} is not registered", Name); } await scheduleTaskService.UpdateTask(task); diff --git a/src/Web/Grand.Web.Common/Startup/TaskHandler.cs b/src/Web/Grand.Web.Common/Startup/TaskHandler.cs index a15da9229..234539e35 100644 --- a/src/Web/Grand.Web.Common/Startup/TaskHandler.cs +++ b/src/Web/Grand.Web.Common/Startup/TaskHandler.cs @@ -1,8 +1,6 @@ using Grand.Business.Core.Interfaces.System.ScheduleTasks; using Grand.Data; -using Grand.Infrastructure.Configuration; -using Grand.Infrastructure.Plugins; -using Grand.Infrastructure.TypeSearch; +using Grand.Web.Common.Extensions; using Grand.Web.Common.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -17,20 +15,11 @@ public static void RegisterTasks(this IServiceCollection services, IConfiguratio //database is already installed, so start scheduled tasks if (!DataSettingsManager.DatabaseIsInstalled()) return; - var appConfig = new AppConfig(); - configuration.GetSection("Application").Bind(appConfig); + var scheduleTaskKeyedServices = KeyedServiceHelper.GetKeyedServicesForInterface(services); - var typeSearcher = new TypeSearcher(); - var scheduleTasks = typeSearcher.ClassesOfType(); - - var scheduleTasksInstalled = scheduleTasks - .Where(PluginExtensions.OnlyInstalledPlugins); //ignore not installed plugins - - foreach (var task in scheduleTasksInstalled) + foreach (var task in scheduleTaskKeyedServices) { - var assemblyName = task.Assembly.GetName().Name; - services.AddSingleton(sp => - new BackgroundServiceTask($"{task.FullName}, {assemblyName}", sp)); + services.AddSingleton(sp => new BackgroundServiceTask(task, sp)); } } } \ No newline at end of file