mirror of https://github.com/abpframework/abp.git
6 changed files with 184 additions and 5 deletions
@ -0,0 +1,96 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using TickerQ.Utilities.Enums; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.TickerQ; |
||||
|
|
||||
|
namespace Volo.Abp.BackgroundWorkers.TickerQ; |
||||
|
|
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
[ExposeServices(typeof(IBackgroundWorkerManager), typeof(TickerQBackgroundWorkerManager))] |
||||
|
public class TickerQBackgroundWorkerManager : BackgroundWorkerManager, ISingletonDependency |
||||
|
{ |
||||
|
protected IObjectAccessor<IServiceCollection> ObjectAccessor { get; } |
||||
|
|
||||
|
public TickerQBackgroundWorkerManager(IObjectAccessor<IServiceCollection> objectAccessor) |
||||
|
{ |
||||
|
ObjectAccessor = objectAccessor; |
||||
|
} |
||||
|
|
||||
|
public override async Task AddAsync(IBackgroundWorker worker, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
if (worker is AsyncPeriodicBackgroundWorkerBase or PeriodicBackgroundWorkerBase) |
||||
|
{ |
||||
|
int? period = null; |
||||
|
string? cronExpression = null; |
||||
|
|
||||
|
if (worker is AsyncPeriodicBackgroundWorkerBase asyncPeriodicBackgroundWorkerBase) |
||||
|
{ |
||||
|
period = asyncPeriodicBackgroundWorkerBase.Period; |
||||
|
cronExpression = asyncPeriodicBackgroundWorkerBase.CronExpression; |
||||
|
} |
||||
|
else if (worker is PeriodicBackgroundWorkerBase periodicBackgroundWorkerBase) |
||||
|
{ |
||||
|
period = periodicBackgroundWorkerBase.Period; |
||||
|
cronExpression = periodicBackgroundWorkerBase.CronExpression; |
||||
|
} |
||||
|
|
||||
|
if (period == null && cronExpression.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
throw new AbpException($"Both 'Period' and 'CronExpression' are not set for {worker.GetType().FullName}. You must set at least one of them."); |
||||
|
} |
||||
|
|
||||
|
if (period != null && cronExpression.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
cronExpression = GetCron(period.Value); |
||||
|
} |
||||
|
|
||||
|
ObjectAccessor.Value!.PreConfigure<AbpTickerQOptions>(options => |
||||
|
{ |
||||
|
var name = BackgroundWorkerNameAttribute.GetNameOrNull(worker.GetType()) ?? worker.GetType().FullName; |
||||
|
options.Functions.TryAdd(name!, (cronExpression!, TickerTaskPriority.Normal, async (tickerQCancellationToken, serviceProvider, tickerFunctionContext) => |
||||
|
{ |
||||
|
var workerInvoker = new TickerQPeriodicBackgroundWorkerInvoker(worker, serviceProvider); |
||||
|
await workerInvoker.DoWorkAsync(tickerFunctionContext, tickerQCancellationToken); |
||||
|
})); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
await base.AddAsync(worker, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
protected virtual string GetCron(int period) |
||||
|
{ |
||||
|
var time = TimeSpan.FromMilliseconds(period); |
||||
|
if (time.TotalMinutes < 1) |
||||
|
{ |
||||
|
// Less than 1 minute — 5-field cron doesn't support seconds, so run every minute
|
||||
|
return "* * * * *"; |
||||
|
} |
||||
|
|
||||
|
if (time.TotalMinutes < 60) |
||||
|
{ |
||||
|
// Run every N minutes
|
||||
|
var minutes = (int)Math.Round(time.TotalMinutes); |
||||
|
return $"*/{minutes} * * * *"; |
||||
|
} |
||||
|
|
||||
|
if (time.TotalHours < 24) |
||||
|
{ |
||||
|
// Run every N hours
|
||||
|
var hours = (int)Math.Round(time.TotalHours); |
||||
|
return $"0 */{hours} * * *"; |
||||
|
} |
||||
|
|
||||
|
if (time.TotalDays <= 31) |
||||
|
{ |
||||
|
// Run every N days
|
||||
|
var days = (int)Math.Round(time.TotalDays); |
||||
|
return $"0 0 */{days} * *"; |
||||
|
} |
||||
|
|
||||
|
throw new AbpException($"Cannot convert period: {period} to cron expression."); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
using System; |
||||
|
using System.Reflection; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using TickerQ.Utilities.Models; |
||||
|
|
||||
|
namespace Volo.Abp.BackgroundWorkers.TickerQ; |
||||
|
|
||||
|
//TODO: Use lambda expression to improve performance.
|
||||
|
public class TickerQPeriodicBackgroundWorkerInvoker |
||||
|
{ |
||||
|
private readonly MethodInfo _doWorkAsyncMethod; |
||||
|
private readonly MethodInfo _doWorkMethod; |
||||
|
|
||||
|
protected IBackgroundWorker Worker { get; } |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
|
||||
|
public TickerQPeriodicBackgroundWorkerInvoker(IBackgroundWorker worker, IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
_doWorkAsyncMethod = worker.GetType().GetMethod("DoWorkAsync", BindingFlags.Instance | BindingFlags.NonPublic)!; |
||||
|
_doWorkMethod = worker.GetType().GetMethod("DoWork", BindingFlags.Instance | BindingFlags.NonPublic)!; |
||||
|
|
||||
|
Worker = worker; |
||||
|
ServiceProvider = serviceProvider; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task DoWorkAsync(TickerFunctionContext context, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var workerContext = new PeriodicBackgroundWorkerContext(ServiceProvider); |
||||
|
switch (Worker) |
||||
|
{ |
||||
|
case AsyncPeriodicBackgroundWorkerBase asyncPeriodicBackgroundWorker: |
||||
|
await (Task)(_doWorkAsyncMethod.Invoke(asyncPeriodicBackgroundWorker, new object[] { workerContext })!); |
||||
|
break; |
||||
|
case PeriodicBackgroundWorkerBase periodicBackgroundWorker: |
||||
|
_doWorkMethod.Invoke(periodicBackgroundWorker, new object[] { workerContext }); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using TickerQ.Utilities; |
||||
|
using TickerQ.Utilities.Enums; |
||||
|
|
||||
|
namespace Volo.Abp.TickerQ; |
||||
|
|
||||
|
public class AbpTickerQOptions |
||||
|
{ |
||||
|
public Dictionary<string, (string, TickerTaskPriority, TickerFunctionDelegate)> Functions { get;} |
||||
|
|
||||
|
public Dictionary<string, (string, Type)> RequestTypes { get; } |
||||
|
|
||||
|
public AbpTickerQOptions() |
||||
|
{ |
||||
|
Functions = new Dictionary<string, (string, TickerTaskPriority, TickerFunctionDelegate)>(); |
||||
|
RequestTypes = new Dictionary<string, (string, Type)>(); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue