diff --git a/docs/en/framework/infrastructure/background-jobs/tickerq.md b/docs/en/framework/infrastructure/background-jobs/tickerq.md index c7eb5d7dd6..a8e69150be 100644 --- a/docs/en/framework/infrastructure/background-jobs/tickerq.md +++ b/docs/en/framework/infrastructure/background-jobs/tickerq.md @@ -42,6 +42,31 @@ public class YourModule : AbpModule ## Configuration +### AddTickerQ + +You can call the `AddTickerQ` extension method in the `ConfigureServices` method of your module to configure TickerQ services: + +> This is optional. ABP will automatically register TickerQ services. + +```csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + context.Services.AddTickerQ(x => + { + // Configure TickerQ options here + }); +} +``` + +### UseAbpTickerQ + +You need to call the `UseAbpTickerQ` extension method instead of `AddTickerQ` in the `OnApplicationInitialization` method of your module: + +```csharp +// (default: TickerQStartMode.Immediate) +app.UseAbpTickerQ(startMode: ...); +``` + ### AbpBackgroundJobsTickerQOptions You can configure the `TimeTicker` properties for specific jobs. For example, Change `Priority`, `Retries` and `RetryIntervals` properties: @@ -49,14 +74,18 @@ You can configure the `TimeTicker` properties for specific jobs. For example, Ch ```csharp Configure(options => { - options.AddJobConfiguration(new AbpBackgroundJobsTimeTickerConfiguration() + options.AddJobConfiguration(new AbpBackgroundJobsTimeTickerConfiguration() { Retries = 3, RetryIntervals = new[] {30, 60, 120}, // Retry after 30s, 60s, then 2min Priority = TickerTaskPriority.High + + // Optional batching + //BatchParent = Guid.Parse("...."), + //BatchRunCondition = BatchRunCondition.OnSuccess }); - options.AddJobConfiguration(new AbpBackgroundJobsTimeTickerConfiguration() + options.AddJobConfiguration(new AbpBackgroundJobsTimeTickerConfiguration() { Retries = 5, RetryIntervals = new[] {30, 60, 120}, // Retry after 30s, 60s, then 2min @@ -65,6 +94,54 @@ Configure(options => }); ``` +### Add your own TickerQ Background Jobs Definitions + +ABP will handle the TickerQ job definitions by `AbpTickerQFunctionProvider` service. You shouldn't use `TickerFunction` to add your own job definitions. You can inject and use the `AbpTickerQFunctionProvider` to add your own definitions and use `ITimeTickerManager` or `ICronTickerManager` to manage the jobs. + +For example, you can add a `CleanupJobs` job definition in the `OnPreApplicationInitializationAsync` method of your module: + +```csharp +public class CleanupJobs +{ + public async Task CleanupLogsAsync(TickerFunctionContext tickerContext, CancellationToken cancellationToken) + { + var logFileName = tickerContext.Request; + Console.WriteLine($"Cleaning up log file: {logFileName} at {DateTime.Now}"); + } +} +``` + +```csharp +public override Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context) +{ + var abpTickerQFunctionProvider = context.ServiceProvider.GetRequiredService(); + abpTickerQFunctionProvider.Functions.TryAdd(nameof(CleanupJobs), (string.Empty, TickerTaskPriority.Normal, new TickerFunctionDelegate(async (cancellationToken, serviceProvider, tickerFunctionContext) => + { + var service = new CleanupJobs(); // Or get it from the serviceProvider + var request = await TickerRequestProvider.GetRequestAsync(serviceProvider, tickerFunctionContext.Id, tickerFunctionContext.Type); + var genericContext = new TickerFunctionContext(tickerFunctionContext, request); + await service.CleanupLogsAsync(genericContext, cancellationToken); + }))); + abpTickerQFunctionProvider.RequestTypes.TryAdd(nameof(CleanupJobs), (typeof(string).FullName, typeof(string))); + return Task.CompletedTask; +} +``` + +And then you can add a job by using the `ITimeTickerManager`: + +```csharp +var timeTickerManager = context.ServiceProvider.GetRequiredService>(); +await timeTickerManager.AddAsync(new TimeTicker +{ + Function = nameof(CleanupJobs), + ExecutionTime = DateTime.UtcNow.AddSeconds(5), + Request = TickerHelper.CreateTickerRequest("cleanup_example_file.txt"), + Retries = 3, + RetryIntervals = new[] { 30, 60, 120 }, // Retry after 30s, 60s, then 2min +}); +``` + ### TickerQ Dashboard and EF Core Integration You can install the [TickerQ dashboard](https://tickerq.net/setup/dashboard.html) and [Entity Framework Core](https://tickerq.net/setup/tickerq-ef-core.html) integration by its documentation. There is no specific configuration needed for the ABP integration. + diff --git a/docs/en/framework/infrastructure/background-workers/tickerq.md b/docs/en/framework/infrastructure/background-workers/tickerq.md index 30ec07f9ee..adc9269052 100644 --- a/docs/en/framework/infrastructure/background-workers/tickerq.md +++ b/docs/en/framework/infrastructure/background-workers/tickerq.md @@ -40,4 +40,102 @@ public class YourModule : AbpModule ## Configuration -TODO: \ No newline at end of file +### AddTickerQ + +You can call the `AddTickerQ` extension method in the `ConfigureServices` method of your module to configure TickerQ services: + +> This is optional. ABP will automatically register TickerQ services. + +```csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + context.Services.AddTickerQ(x => + { + // Configure TickerQ options here + }); +} +``` + +### UseAbpTickerQ + +You need to call the `UseAbpTickerQ` extension method instead of `AddTickerQ` in the `OnApplicationInitialization` method of your module: + +```csharp +// (default: TickerQStartMode.Immediate) +app.UseAbpTickerQ(startMode: ...); +``` + +### AbpBackgroundWorkersTickerQOptions + +You can configure the `CronTicker` properties for specific jobs. For example, Change `Priority`, `Retries` and `RetryIntervals` properties: + +```csharp +Configure(options => +{ + options.AddConfiguration(new AbpBackgroundWorkersCronTickerConfiguration() + { + Retries = 3, + RetryIntervals = new[] {30, 60, 120}, // Retry after 30s, 60s, then 2min, + Priority = TickerTaskPriority.High + }); +}); +``` + +### Add your own TickerQ Background Worker Definitions + +ABP will handle the TickerQ job definitions by `AbpTickerQFunctionProvider` service. You shouldn't use `TickerFunction` to add your own job definitions. You can inject and use the `AbpTickerQFunctionProvider` to add your own definitions and use `ITimeTickerManager` or `ICronTickerManager` to manage the jobs. + +For example, you can add a `CleanupJobs` job definition in the `OnPreApplicationInitializationAsync` method of your module: + +```csharp +public class CleanupJobs +{ + public async Task CleanupLogsAsync(TickerFunctionContext tickerContext, CancellationToken cancellationToken) + { + var logFileName = tickerContext.Request; + Console.WriteLine($"Cleaning up log file: {logFileName} at {DateTime.Now}"); + } +} +``` + +```csharp +public override Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context) +{ + var abpTickerQFunctionProvider = context.ServiceProvider.GetRequiredService(); + abpTickerQFunctionProvider.Functions.TryAdd(nameof(CleanupJobs), (string.Empty, TickerTaskPriority.Normal, new TickerFunctionDelegate(async (cancellationToken, serviceProvider, tickerFunctionContext) => + { + var service = new CleanupJobs(); // Or get it from the serviceProvider + var request = await TickerRequestProvider.GetRequestAsync(serviceProvider, tickerFunctionContext.Id, tickerFunctionContext.Type); + var genericContext = new TickerFunctionContext(tickerFunctionContext, request); + await service.CleanupLogsAsync(genericContext, cancellationToken); + }))); + abpTickerQFunctionProvider.RequestTypes.TryAdd(nameof(CleanupJobs), (typeof(string).FullName, typeof(string))); + return Task.CompletedTask; +} +``` + +And then you can add a job by using the `ICronTickerManager`: + +```csharp +var cronTickerManager = context.ServiceProvider.GetRequiredService>(); +await cronTickerManager.AddAsync(new CronTicker +{ + Function = nameof(CleanupJobs), + Expression = "0 */6 * * *", // Every 6 hours + Request = TickerHelper.CreateTickerRequest("cleanup_example_file.txt"), + Retries = 2, + RetryIntervals = new[] { 60, 300 } +}); +``` + +You can specify a cron expression instead of use `ICronTickerManager` to add a worker: + +```csharp +abpTickerQFunctionProvider.Functions.TryAdd(nameof(CleanupJobs), (string.Empty, TickerTaskPriority.Normal, new TickerFunctionDelegate(async (cancellationToken, serviceProvider, tickerFunctionContext) => +{ + var service = new CleanupJobs(); + var request = await TickerRequestProvider.GetRequestAsync(serviceProvider, tickerFunctionContext.Id, tickerFunctionContext.Type); + var genericContext = new TickerFunctionContext(tickerFunctionContext, request); + await service.CleanupLogsAsync(genericContext, cancellationToken); +}))); +``` diff --git a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTickerQModule.cs b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTickerQModule.cs index a47a17273e..cd94bae7a7 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTickerQModule.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTickerQModule.cs @@ -26,7 +26,7 @@ public class AbpBackgroundJobsTickerQModule : AbpModule { var genericMethod = GetTickerFunctionDelegateMethod.MakeGenericMethod(jobConfiguration.ArgsType); var tickerFunctionDelegate = (TickerFunctionDelegate)genericMethod.Invoke(null, [jobConfiguration.ArgsType])!; - var config = abpBackgroundJobsTickerQOptions.Value.GetJobConfigurationOrNull(jobConfiguration.JobType); + var config = abpBackgroundJobsTickerQOptions.Value.GetConfigurationOrNull(jobConfiguration.JobType); tickerFunctionDelegates.TryAdd(jobConfiguration.JobName, (string.Empty, config?.Priority ?? TickerTaskPriority.Normal, tickerFunctionDelegate)); requestTypes.TryAdd(jobConfiguration.JobName, (jobConfiguration.ArgsType.FullName, jobConfiguration.ArgsType)!); } diff --git a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTickerQOptions.cs b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTickerQOptions.cs index 3db33afa4a..f85b3e5fef 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTickerQOptions.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTickerQOptions.cs @@ -5,30 +5,30 @@ namespace Volo.Abp.BackgroundJobs.TickerQ; public class AbpBackgroundJobsTickerQOptions { - private readonly Dictionary _jobConfigurations; + private readonly Dictionary _configurations; public AbpBackgroundJobsTickerQOptions() { - _jobConfigurations = new Dictionary(); + _configurations = new Dictionary(); } - public void AddJobConfiguration(AbpBackgroundJobsTimeTickerConfiguration configuration) + public void AddConfiguration(AbpBackgroundJobsTimeTickerConfiguration configuration) { - AddJobConfiguration(typeof(TJob), configuration); + AddConfiguration(typeof(TJob), configuration); } - public void AddJobConfiguration(Type jobType, AbpBackgroundJobsTimeTickerConfiguration configuration) + public void AddConfiguration(Type jobType, AbpBackgroundJobsTimeTickerConfiguration configuration) { - _jobConfigurations[jobType] = configuration; + _configurations[jobType] = configuration; } - public AbpBackgroundJobsTimeTickerConfiguration? GetJobConfigurationOrNull() + public AbpBackgroundJobsTimeTickerConfiguration? GetConfigurationOrNull() { - return GetJobConfigurationOrNull(typeof(TJob)); + return GetConfigurationOrNull(typeof(TJob)); } - public AbpBackgroundJobsTimeTickerConfiguration? GetJobConfigurationOrNull(Type jobType) + public AbpBackgroundJobsTimeTickerConfiguration? GetConfigurationOrNull(Type jobType) { - return _jobConfigurations.GetValueOrDefault(jobType); + return _configurations.GetValueOrDefault(jobType); } } diff --git a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTimeTickerConfiguration.cs b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTimeTickerConfiguration.cs index ed42c01a3e..65b150ea48 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTimeTickerConfiguration.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpBackgroundJobsTimeTickerConfiguration.cs @@ -1,3 +1,4 @@ +using System; using TickerQ.Utilities.Enums; namespace Volo.Abp.BackgroundJobs.TickerQ; @@ -9,4 +10,8 @@ public class AbpBackgroundJobsTimeTickerConfiguration public int[]? RetryIntervals { get; set; } public TickerTaskPriority? Priority { get; set; } + + public Guid? BatchParent { get; set; } + + public BatchRunCondition? BatchRunCondition { get; set; } } diff --git a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/TickerQBackgroundJobManager.cs b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpTickerQBackgroundJobManager.cs similarity index 66% rename from framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/TickerQBackgroundJobManager.cs rename to framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpTickerQBackgroundJobManager.cs index 1be41bae67..3643c56709 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/TickerQBackgroundJobManager.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpTickerQBackgroundJobManager.cs @@ -1,5 +1,7 @@ using System; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using TickerQ.Utilities; using TickerQ.Utilities.Interfaces.Managers; @@ -9,17 +11,21 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.BackgroundJobs.TickerQ; [Dependency(ReplaceServices = true)] -public class TickerQBackgroundJobManager : IBackgroundJobManager, ITransientDependency +public class AbpTickerQBackgroundJobManager : IBackgroundJobManager, ITransientDependency { + public ILogger Logger { get; set; } + protected ITimeTickerManager TimeTickerManager { get; } protected AbpBackgroundJobOptions Options { get; } protected AbpBackgroundJobsTickerQOptions TickerQOptions { get; } - public TickerQBackgroundJobManager( + public AbpTickerQBackgroundJobManager( ITimeTickerManager timeTickerManager, IOptions options, IOptions tickerQOptions) { + Logger = NullLogger.Instance; + TimeTickerManager = timeTickerManager; Options = options.Value; TickerQOptions = tickerQOptions.Value; @@ -36,14 +42,23 @@ public class TickerQBackgroundJobManager : IBackgroundJobManager, ITransientDepe Request = TickerHelper.CreateTickerRequest(args), }; - var config = TickerQOptions.GetJobConfigurationOrNull(job.JobType); + var config = TickerQOptions.GetConfigurationOrNull(job.JobType); if (config != null) { timeTicker.Retries = config.Retries ?? timeTicker.Retries; timeTicker.RetryIntervals = config.RetryIntervals ?? timeTicker.RetryIntervals; + timeTicker.BatchParent = config.BatchParent ?? timeTicker.BatchParent; + timeTicker.BatchRunCondition = config.BatchRunCondition ?? timeTicker.BatchRunCondition; } var result = await TimeTickerManager.AddAsync(timeTicker); - return !result.IsSucceded ? throw result.Exception : result.Result.Id.ToString(); + + if (!result.IsSucceded) + { + Logger.LogException(result.Exception); + return timeTicker.Id.ToString(); + } + + return result.Result.Id.ToString(); } } diff --git a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersCronTickerConfiguration.cs b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersCronTickerConfiguration.cs new file mode 100644 index 0000000000..0e8ed89a14 --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersCronTickerConfiguration.cs @@ -0,0 +1,12 @@ +using TickerQ.Utilities.Enums; + +namespace Volo.Abp.BackgroundWorkers.TickerQ; + +public class AbpBackgroundWorkersCronTickerConfiguration +{ + public int? Retries { get; set; } + + public int[]? RetryIntervals { get; set; } + + public TickerTaskPriority? Priority { get; set; } +} diff --git a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersTickerQModule.cs b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersTickerQModule.cs index 21edb7836a..c223b49867 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersTickerQModule.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersTickerQModule.cs @@ -1,4 +1,10 @@ -using Volo.Abp.Modularity; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using TickerQ.Utilities.Interfaces.Managers; +using TickerQ.Utilities.Models.Ticker; +using Volo.Abp.Modularity; using Volo.Abp.TickerQ; namespace Volo.Abp.BackgroundWorkers.TickerQ; @@ -6,5 +12,32 @@ namespace Volo.Abp.BackgroundWorkers.TickerQ; [DependsOn(typeof(AbpBackgroundWorkersModule), typeof(AbpTickerQModule))] public class AbpBackgroundWorkersTickerQModule : AbpModule { + public override async Task OnPostApplicationInitializationAsync(ApplicationInitializationContext context) + { + var abpTickerQBackgroundWorkersProvider = context.ServiceProvider.GetRequiredService(); + var cronTickerManager = context.ServiceProvider.GetRequiredService>(); + var abpBackgroundWorkersTickerQOptions = context.ServiceProvider.GetRequiredService>().Value; + foreach (var backgroundWorker in abpTickerQBackgroundWorkersProvider.BackgroundWorkers) + { + var cronTicker = new CronTicker + { + Function = backgroundWorker.Value.Function, + Expression = backgroundWorker.Value.CronExpression + }; + var config = abpBackgroundWorkersTickerQOptions.GetConfigurationOrNull(backgroundWorker.Value.WorkerType); + if (config != null) + { + cronTicker.Retries = config.Retries ?? cronTicker.Retries; + cronTicker.RetryIntervals = config.RetryIntervals ?? cronTicker.RetryIntervals; + } + + var result = await cronTickerManager.AddAsync(cronTicker); + if (!result.IsSucceded) + { + var logger = context.ServiceProvider.GetRequiredService>(); + logger.LogException(result.Exception); + } + } + } } diff --git a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersTickerQOptions.cs b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersTickerQOptions.cs new file mode 100644 index 0000000000..44c7e28734 --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersTickerQOptions.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.BackgroundWorkers.TickerQ; + +public class AbpBackgroundWorkersTickerQOptions +{ + private readonly Dictionary _onfigurations; + + public AbpBackgroundWorkersTickerQOptions() + { + _onfigurations = new Dictionary(); + } + + public void AddConfiguration(AbpBackgroundWorkersCronTickerConfiguration configuration) + { + AddConfiguration(typeof(TJob), configuration); + } + + public void AddConfiguration(Type jobType, AbpBackgroundWorkersCronTickerConfiguration configuration) + { + _onfigurations[jobType] = configuration; + } + + public AbpBackgroundWorkersCronTickerConfiguration? GetConfigurationOrNull() + { + return GetConfigurationOrNull(typeof(TJob)); + } + + public AbpBackgroundWorkersCronTickerConfiguration? GetConfigurationOrNull(Type jobType) + { + return _onfigurations.GetValueOrDefault(jobType); + } +} diff --git a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/TickerQBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQBackgroundWorkerManager.cs similarity index 67% rename from framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/TickerQBackgroundWorkerManager.cs rename to framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQBackgroundWorkerManager.cs index 36cc09d784..8efe64e677 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/TickerQBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQBackgroundWorkerManager.cs @@ -1,21 +1,30 @@ using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Options; using TickerQ.Utilities.Enums; using Volo.Abp.DependencyInjection; +using Volo.Abp.DynamicProxy; using Volo.Abp.TickerQ; namespace Volo.Abp.BackgroundWorkers.TickerQ; [Dependency(ReplaceServices = true)] -[ExposeServices(typeof(IBackgroundWorkerManager), typeof(TickerQBackgroundWorkerManager))] -public class TickerQBackgroundWorkerManager : BackgroundWorkerManager, ISingletonDependency +[ExposeServices(typeof(IBackgroundWorkerManager), typeof(AbpTickerQBackgroundWorkerManager))] +public class AbpTickerQBackgroundWorkerManager : BackgroundWorkerManager, ISingletonDependency { protected AbpTickerQFunctionProvider AbpTickerQFunctionProvider { get; } + protected AbpTickerQBackgroundWorkersProvider AbpTickerQBackgroundWorkersProvider { get; } + protected AbpBackgroundWorkersTickerQOptions Options { get; } - public TickerQBackgroundWorkerManager(AbpTickerQFunctionProvider abpTickerQFunctionProvider) + public AbpTickerQBackgroundWorkerManager( + AbpTickerQFunctionProvider abpTickerQFunctionProvider, + AbpTickerQBackgroundWorkersProvider abpTickerQBackgroundWorkersProvider, + IOptions options) { AbpTickerQFunctionProvider = abpTickerQFunctionProvider; + AbpTickerQBackgroundWorkersProvider = abpTickerQBackgroundWorkersProvider; + Options = options.Value; } public override async Task AddAsync(IBackgroundWorker worker, CancellationToken cancellationToken = default) @@ -43,11 +52,20 @@ public class TickerQBackgroundWorkerManager : BackgroundWorkerManager, ISingleto cronExpression = cronExpression ?? GetCron(period!.Value); var name = BackgroundWorkerNameAttribute.GetNameOrNull(worker.GetType()) ?? worker.GetType().FullName; - AbpTickerQFunctionProvider.Functions.TryAdd(name!, (cronExpression!, TickerTaskPriority.LongRunning, async (tickerQCancellationToken, serviceProvider, tickerFunctionContext) => + + var config = Options.GetConfigurationOrNull(ProxyHelper.GetUnProxiedType(worker)); + AbpTickerQFunctionProvider.Functions.TryAdd(name!, (string.Empty, config?.Priority ?? TickerTaskPriority.LongRunning, async (tickerQCancellationToken, serviceProvider, tickerFunctionContext) => { - var workerInvoker = new TickerQPeriodicBackgroundWorkerInvoker(worker, serviceProvider); + var workerInvoker = new AbpTickerQPeriodicBackgroundWorkerInvoker(worker, serviceProvider); await workerInvoker.DoWorkAsync(tickerFunctionContext, tickerQCancellationToken); })); + + AbpTickerQBackgroundWorkersProvider.BackgroundWorkers.Add(name!, new AbpTickerQCronBackgroundWorker + { + Function = name!, + CronExpression = cronExpression, + WorkerType = ProxyHelper.GetUnProxiedType(worker) + }); } await base.AddAsync(worker, cancellationToken); diff --git a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQBackgroundWorkersProvider.cs b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQBackgroundWorkersProvider.cs new file mode 100644 index 0000000000..3c0fe763ec --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQBackgroundWorkersProvider.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.BackgroundWorkers.TickerQ; + +public class AbpTickerQBackgroundWorkersProvider : ISingletonDependency +{ + public Dictionary BackgroundWorkers { get;} + + public AbpTickerQBackgroundWorkersProvider() + { + BackgroundWorkers = new Dictionary(); + } +} diff --git a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQCronBackgroundWorker.cs b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQCronBackgroundWorker.cs new file mode 100644 index 0000000000..55c97a00a6 --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQCronBackgroundWorker.cs @@ -0,0 +1,12 @@ +using System; + +namespace Volo.Abp.BackgroundWorkers.TickerQ; + +public class AbpTickerQCronBackgroundWorker +{ + public string Function { get; set; } = null!; + + public string CronExpression { get; set; } = null!; + + public Type WorkerType { get; set; } = null!; +} diff --git a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/TickerQPeriodicBackgroundWorkerInvoker.cs b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQPeriodicBackgroundWorkerInvoker.cs similarity index 89% rename from framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/TickerQPeriodicBackgroundWorkerInvoker.cs rename to framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQPeriodicBackgroundWorkerInvoker.cs index ae52032b9a..5615609606 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/TickerQPeriodicBackgroundWorkerInvoker.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQPeriodicBackgroundWorkerInvoker.cs @@ -7,7 +7,7 @@ using TickerQ.Utilities.Models; namespace Volo.Abp.BackgroundWorkers.TickerQ; //TODO: Use lambda expression to improve performance. -public class TickerQPeriodicBackgroundWorkerInvoker +public class AbpTickerQPeriodicBackgroundWorkerInvoker { private readonly MethodInfo _doWorkAsyncMethod; private readonly MethodInfo _doWorkMethod; @@ -15,7 +15,7 @@ public class TickerQPeriodicBackgroundWorkerInvoker protected IBackgroundWorker Worker { get; } protected IServiceProvider ServiceProvider { get; } - public TickerQPeriodicBackgroundWorkerInvoker(IBackgroundWorker worker, IServiceProvider serviceProvider) + public AbpTickerQPeriodicBackgroundWorkerInvoker(IBackgroundWorker worker, IServiceProvider serviceProvider) { _doWorkAsyncMethod = worker.GetType().GetMethod("DoWorkAsync", BindingFlags.Instance | BindingFlags.NonPublic)!; _doWorkMethod = worker.GetType().GetMethod("DoWork", BindingFlags.Instance | BindingFlags.NonPublic)!; diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/CleanupJobs.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/CleanupJobs.cs new file mode 100644 index 0000000000..6eca55e09f --- /dev/null +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/CleanupJobs.cs @@ -0,0 +1,15 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using TickerQ.Utilities.Models; + +namespace Volo.Abp.BackgroundJobs.DemoApp.TickerQ; + +public class CleanupJobs +{ + public async Task CleanupLogsAsync(TickerFunctionContext tickerContext, CancellationToken cancellationToken) + { + var logFileName = tickerContext.Request; + Console.WriteLine($"Cleaning up log file: {logFileName} at {DateTime.Now}"); + } +} diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/DemoAppTickerQModule.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/DemoAppTickerQModule.cs index f25dc778b7..c9a3b957de 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/DemoAppTickerQModule.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.TickerQ/DemoAppTickerQModule.cs @@ -1,10 +1,14 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using TickerQ.Dashboard.DependencyInjection; using TickerQ.DependencyInjection; +using TickerQ.Utilities; +using TickerQ.Utilities.Enums; using TickerQ.Utilities.Interfaces.Managers; +using TickerQ.Utilities.Models; using TickerQ.Utilities.Models.Ticker; using Volo.Abp.AspNetCore; using Volo.Abp.Autofac; @@ -14,6 +18,7 @@ using Volo.Abp.BackgroundJobs.TickerQ; using Volo.Abp.BackgroundWorkers; using Volo.Abp.BackgroundWorkers.TickerQ; using Volo.Abp.Modularity; +using Volo.Abp.TickerQ; namespace Volo.Abp.BackgroundJobs.DemoApp.TickerQ; @@ -42,18 +47,43 @@ public class DemoAppTickerQModule : AbpModule Configure(options => { - options.AddJobConfiguration(new AbpBackgroundJobsTimeTickerConfiguration() + options.AddConfiguration(new AbpBackgroundJobsTimeTickerConfiguration() { Retries = 3, - RetryIntervals = new[] {30, 60, 120}, // Retry after 30s, 60s, then 2min + RetryIntervals = new[] {30, 60, 120}, // Retry after 30s, 60s, then 2min, + Priority = TickerTaskPriority.High }); - options.AddJobConfiguration(new AbpBackgroundJobsTimeTickerConfiguration() + options.AddConfiguration(new AbpBackgroundJobsTimeTickerConfiguration() { Retries = 5, RetryIntervals = new[] {30, 60, 120}, // Retry after 30s, 60s, then 2min }); }); + + Configure(options => + { + options.AddConfiguration(new AbpBackgroundWorkersCronTickerConfiguration() + { + Retries = 3, + RetryIntervals = new[] {30, 60, 120}, // Retry after 30s, 60s, then 2min, + Priority = TickerTaskPriority.High + }); + }); + } + + public override Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context) + { + var abpTickerQFunctionProvider = context.ServiceProvider.GetRequiredService(); + abpTickerQFunctionProvider.Functions.TryAdd(nameof(CleanupJobs), (string.Empty, TickerTaskPriority.Normal, new TickerFunctionDelegate(async (cancellationToken, serviceProvider, tickerFunctionContext) => + { + var service = new CleanupJobs(); + var request = await TickerRequestProvider.GetRequestAsync(serviceProvider, tickerFunctionContext.Id, tickerFunctionContext.Type); + var genericContext = new TickerFunctionContext(tickerFunctionContext, request); + await service.CleanupLogsAsync(genericContext, cancellationToken); + }))); + abpTickerQFunctionProvider.RequestTypes.TryAdd(nameof(CleanupJobs), (typeof(string).FullName, typeof(string))); + return Task.CompletedTask; } public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context) @@ -64,6 +94,26 @@ public class DemoAppTickerQModule : AbpModule var app = context.GetApplicationBuilder(); app.UseAbpTickerQ(); + var timeTickerManager = context.ServiceProvider.GetRequiredService>(); + await timeTickerManager.AddAsync(new TimeTicker + { + Function = nameof(CleanupJobs), + ExecutionTime = DateTime.UtcNow.AddSeconds(5), + Request = TickerHelper.CreateTickerRequest("cleanup_example_file.txt"), + Retries = 3, + RetryIntervals = new[] { 30, 60, 120 }, // Retry after 30s, 60s, then 2min + }); + + var cronTickerManager = context.ServiceProvider.GetRequiredService>(); + await cronTickerManager.AddAsync(new CronTicker + { + Function = nameof(CleanupJobs), + Expression = "* * * * *", // Every minute + Request = TickerHelper.CreateTickerRequest("cleanup_example_file.txt"), + Retries = 2, + RetryIntervals = new[] { 60, 300 } + }); + app.UseRouting(); app.UseEndpoints(endpoints => {