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