Browse Source

feat(tasks): added preconfiguration interface for built-in jobs in the framework

pull/793/head
cKey 3 years ago
parent
commit
6bedb2e40c
  1. 11
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs
  2. 8
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobDispatcherSelectorList.cs
  3. 7
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobDispatcherSelectorList.cs
  4. 122
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobDispatcherSelectorListExtensions.cs
  5. 61
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobTypeSelector.cs
  6. 24
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobManager.cs
  7. 31
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundWorkerManager.cs
  8. 81
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobDispatcherSelectorListExtensions.cs
  9. 9
      aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs

11
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs

@ -20,6 +20,16 @@ public class AbpBackgroundTasksOptions
/// </remarks>
public ITypeList<IJobDefinitionProvider> DefinitionProviders { get; }
/// <summary>
/// 作业发布预配置
/// </summary>
/// <remarks>
/// Tips: <br />
/// 仅作用于适用于 IBackgroundJobManager与IBackgroundWorker 适配器接口的作业预配置
/// <br />
/// <see cref="IJobRunnable"/> 标准实现的作业参数请通过接口直接管理
/// </remarks>
public IJobDispatcherSelectorList JobDispatcherSelectors { get; }
/// <summary>
/// 启用清理任务
/// </summary>
/// <remarks>
@ -93,5 +103,6 @@ public class AbpBackgroundTasksOptions
JobMonitors = new TypeList<IJobEvent>();
DefinitionProviders = new TypeList<IJobDefinitionProvider>();
JobDispatcherSelectors = new JobDispatcherSelectorList();
}
}

8
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobDispatcherSelectorList.cs

@ -0,0 +1,8 @@
using System.Collections;
using System.Collections.Generic;
namespace LINGYUN.Abp.BackgroundTasks;
public interface IJobDispatcherSelectorList : IList<JobTypeSelector>, ICollection<JobTypeSelector>, IEnumerable<JobTypeSelector>, IEnumerable
{
}

7
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobDispatcherSelectorList.cs

@ -0,0 +1,7 @@
using System.Collections.Generic;
namespace LINGYUN.Abp.BackgroundTasks;
public class JobDispatcherSelectorList : List<JobTypeSelector>, IJobDispatcherSelectorList
{
}

122
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobDispatcherSelectorListExtensions.cs

@ -0,0 +1,122 @@
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Linq;
using Volo.Abp;
namespace LINGYUN.Abp.BackgroundTasks;
public static class JobDispatcherSelectorListExtensions
{
public const string AllJobssSelectorName = "All";
public static void AddNamespace(
[NotNull] this IJobDispatcherSelectorList selectors,
[NotNull] string namespaceName,
[CanBeNull] Action<JobTypeSelector> setup = null)
{
Check.NotNull(selectors, nameof(selectors));
var selectorName = "Namespace:" + namespaceName;
if (selectors.Any(s => s.Name == selectorName))
{
return;
}
var selector = new JobTypeSelector(selectorName, t => t.FullName?.StartsWith(namespaceName) ?? false);
setup?.Invoke(selector);
selectors.Add(selector);
}
public static void Add<TJob>([NotNull] this IJobDispatcherSelectorList selectors, [CanBeNull] Action<JobTypeSelector> setup = null)
where TJob : IJobRunnable
{
Check.NotNull(selectors, nameof(selectors));
var selectorName = "Job:" + typeof(TJob).FullName;
if (selectors.Any(s => s.Name == selectorName))
{
return;
}
var selector = new JobTypeSelector(selectorName, t => typeof(TJob).IsAssignableFrom(t));
setup?.Invoke(selector);
selectors.Add(selector);
}
public static void Remove<TJob>([NotNull] this IJobDispatcherSelectorList selectors)
where TJob : IJobRunnable
{
Check.NotNull(selectors, nameof(selectors));
var selectorName = "Job:" + typeof(TJob).FullName;
selectors.RemoveAll(s => s.Name == selectorName);
}
public static void AddAll([NotNull] this IJobDispatcherSelectorList selectors, [CanBeNull] Action<JobTypeSelector> setup = null)
{
Check.NotNull(selectors, nameof(selectors));
if (selectors.Any(s => s.Name == AllJobssSelectorName))
{
return;
}
var selector = new JobTypeSelector(AllJobssSelectorName, t => typeof(IJobRunnable).IsAssignableFrom(t));
setup?.Invoke(selector);
selectors.Add(selector);
}
public static void Add(
[NotNull] this IJobDispatcherSelectorList selectors,
string selectorName,
Func<Type, bool> predicate,
[CanBeNull] Action<JobTypeSelector> setup = null)
{
Check.NotNull(selectors, nameof(selectors));
if (selectors.Any(s => s.Name == selectorName))
{
throw new AbpException($"There is already a selector added before with the same name: {selectorName}");
}
var selector = new JobTypeSelector(selectorName, predicate);
setup?.Invoke(selector);
selectors.Add(selector);
}
public static void Add(
[NotNull] this IJobDispatcherSelectorList selectors,
Func<Type, bool> predicate,
[CanBeNull] Action<JobTypeSelector> setup = null)
{
var selector = new JobTypeSelector(Guid.NewGuid().ToString("N"), predicate);
setup?.Invoke(selector);
selectors.Add(selector);
}
public static bool RemoveByName(
[NotNull] this IJobDispatcherSelectorList selectors,
[NotNull] string name)
{
Check.NotNull(selectors, nameof(selectors));
Check.NotNull(name, nameof(name));
return selectors.RemoveAll(s => s.Name == name).Count > 0;
}
public static bool IsMatch([NotNull] this IJobDispatcherSelectorList selectors, Type jobType)
{
Check.NotNull(selectors, nameof(selectors));
return selectors.Any(s => s.Predicate(jobType));
}
}

61
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobTypeSelector.cs

@ -0,0 +1,61 @@
using System;
using Volo.Abp;
namespace LINGYUN.Abp.BackgroundTasks;
public class JobTypeSelector : NamedTypeSelector
{
public JobTypeSelector(
string name,
Func<Type, bool> predicate,
int lockTimeOut = 0,
string nodeName = null,
string cron = null,
JobPriority priority = JobPriority.Normal,
int interval = 300,
int tryCount = 0,
int maxTryCount = 50)
: base(name, predicate)
{
LockTimeOut = lockTimeOut;
NodeName = nodeName;
Cron = cron;
Priority = priority;
Interval = interval;
TryCount = tryCount;
MaxTryCount = maxTryCount;
}
/// <summary>
/// 任务独占超时时长(秒)
/// 0或更小不生效
/// </summary>
public int LockTimeOut { get; set; }
/// <summary>
/// 指定运行节点
/// </summary>
public string NodeName { get; set; }
/// <summary>
/// 任务优先级
/// </summary>
public JobPriority Priority { get; set; } = JobPriority.Normal;
/// <summary>
/// Cron表达式,如果是周期性任务需要指定
/// </summary>
public string Cron { get; set; }
/// <summary>
/// 间隔时间,单位秒,与Cron表达式冲突
/// 默认: 300
/// </summary>
public int Interval { get; set; } = 300;
/// <summary>
/// 失败重试次数
/// </summary>
public int TryCount { get; set; }
/// <summary>
/// 失败重试上限
/// 默认:50
/// </summary>
public int MaxTryCount { get; set; } = 50;
}

24
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobManager.cs

@ -1,6 +1,7 @@
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection;
@ -81,6 +82,29 @@ public class BackgroundJobManager : IBackgroundJobManager, ITransientDependency
Type = typeof(BackgroundJobAdapter<TArgs>).AssemblyQualifiedName,
};
if (TasksOptions.JobDispatcherSelectors.IsMatch(jobConfiguration.JobType))
{
var selector = TasksOptions
.JobDispatcherSelectors
.FirstOrDefault(x => x.Predicate(jobConfiguration.JobType));
jobInfo.Interval = selector.Interval;
jobInfo.LockTimeOut = selector.LockTimeOut;
jobInfo.Priority = selector.Priority;
jobInfo.TryCount = selector.TryCount;
jobInfo.MaxTryCount = selector.MaxTryCount;
if (!selector.NodeName.IsNullOrWhiteSpace())
{
jobInfo.NodeName = selector.NodeName;
}
if (!selector.Cron.IsNullOrWhiteSpace())
{
jobInfo.Cron = selector.Cron;
}
}
// 存储状态
await JobStore.StoreAsync(jobInfo);

31
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundWorkerManager.cs

@ -1,5 +1,6 @@
using Microsoft.Extensions.Options;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.BackgroundWorkers;
@ -18,19 +19,22 @@ public class BackgroundWorkerManager : IBackgroundWorkerManager, ISingletonDepen
protected IJobPublisher JobPublisher { get; }
protected ICurrentTenant CurrentTenant { get; }
protected AbpBackgroundTasksOptions Options { get; }
protected AbpBackgroundTasksOptions TasksOptions { get; }
public BackgroundWorkerManager(
IClock clock,
IJobStore jobStore,
IJobPublisher jobPublisher,
ICurrentTenant currentTenant,
IOptions<AbpBackgroundTasksOptions> options)
IOptions<AbpBackgroundTasksOptions> options,
IOptions<AbpBackgroundTasksOptions> taskOptions)
{
Clock = clock;
JobStore = jobStore;
JobPublisher = jobPublisher;
CurrentTenant = currentTenant;
Options = options.Value;
TasksOptions = taskOptions.Value;
}
public async Task AddAsync(IBackgroundWorker worker, CancellationToken cancellationToken = default)
@ -50,6 +54,31 @@ public class BackgroundWorkerManager : IBackgroundWorkerManager, ISingletonDepen
jobInfo.BeginTime = Clock.Now;
jobInfo.CreationTime = Clock.Now;
jobInfo.TenantId = CurrentTenant.Id;
var workerType = ProxyHelper.GetUnProxiedType(worker);
if (workerType != null && TasksOptions.JobDispatcherSelectors.IsMatch(workerType))
{
var selector = TasksOptions
.JobDispatcherSelectors
.FirstOrDefault(x => x.Predicate(workerType));
jobInfo.Interval = selector.Interval;
jobInfo.LockTimeOut = selector.LockTimeOut;
jobInfo.Priority = selector.Priority;
jobInfo.TryCount = selector.TryCount;
jobInfo.MaxTryCount = selector.MaxTryCount;
if (!selector.NodeName.IsNullOrWhiteSpace())
{
jobInfo.NodeName = selector.NodeName;
}
if (!selector.Cron.IsNullOrWhiteSpace())
{
jobInfo.Cron = selector.Cron;
}
}
// 存储状态
await JobStore.StoreAsync(jobInfo, cancellationToken);

81
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobDispatcherSelectorListExtensions.cs

@ -0,0 +1,81 @@
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Linq;
using Volo.Abp;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.BackgroundWorkers;
namespace LINGYUN.Abp.BackgroundTasks;
public static class JobDispatcherSelectorListExtensions
{
/// <summary>
///
/// </summary>
/// <typeparam name="TJob"></typeparam>
/// <param name="selectors"></param>
/// <param name="setup"></param>
/// <remarks>
/// Tips: 仅作用于适用于<see cref="IBackgroundJobManager" /> 接口的作业预配置
/// </remarks>
public static void AddJob<TJob>([NotNull] this IJobDispatcherSelectorList selectors, [CanBeNull] Action<JobTypeSelector> setup = null)
{
Check.NotNull(selectors, nameof(selectors));
var selectorName = "Job:" + typeof(TJob).FullName;
if (selectors.Any(s => s.Name == selectorName))
{
return;
}
var selector = new JobTypeSelector(selectorName, t => typeof(TJob).IsAssignableFrom(t));
setup?.Invoke(selector);
selectors.Add(selector);
}
public static void RemoveJob<TJob>([NotNull] this IJobDispatcherSelectorList selectors)
{
Check.NotNull(selectors, nameof(selectors));
var selectorName = "Job:" + typeof(TJob).FullName;
selectors.RemoveAll(s => s.Name == selectorName);
}
/// <summary>
///
/// </summary>
/// <typeparam name="TWorker"></typeparam>
/// <param name="selectors"></param>
/// <param name="setup"></param>
/// <remarks>
/// Tips: 仅作用于适用于<see cref="IBackgroundWorker" /> 接口的作业预配置
/// </remarks>
public static void AddWorker<TWorker>([NotNull] this IJobDispatcherSelectorList selectors, [CanBeNull] Action<JobTypeSelector> setup = null)
where TWorker : IBackgroundWorker
{
Check.NotNull(selectors, nameof(selectors));
var selectorName = "Worker:" + typeof(TWorker).FullName;
if (selectors.Any(s => s.Name == selectorName))
{
return;
}
var selector = new JobTypeSelector(selectorName, t => typeof(TWorker).IsAssignableFrom(t));
setup?.Invoke(selector);
selectors.Add(selector);
}
public static void RemoveWorker<TWorker>([NotNull] this IJobDispatcherSelectorList selectors)
where TWorker : IBackgroundWorker
{
Check.NotNull(selectors, nameof(selectors));
var selectorName = "Worker:" + typeof(TWorker).FullName;
selectors.RemoveAll(s => s.Name == selectorName);
}
}

9
aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs

@ -5,6 +5,7 @@ using LINGYUN.Abp.ExceptionHandling.Emailing;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
using LINGYUN.Abp.Webhooks;
using LINGYUN.Abp.Webhooks.BackgroundJobs;
using LINGYUN.Abp.WebhooksManagement;
using LINGYUN.Abp.Wrapper;
using Medallion.Threading;
@ -130,10 +131,18 @@ public partial class WebhooksManagementHttpApiHostModule
Configure<AbpBackgroundTasksOptions>(options =>
{
options.NodeName = ApplicationName;
options.JobDispatcherSelectors.AddJob<WebhookSenderJob>(
job =>
{
// 让用户自行决定重试次数, 作业管理器限定只执行一次
job.TryCount = 1;
});
//options.JobDispatcherSelectors.AddNamespace(
// "LINGYUN.Abp.Webhooks.BackgroundJobs",
// job =>
// {
// // more
// });
});
}

Loading…
Cancel
Save