Browse Source
1、使作业调度完成时调度用户定义Action,移除污染作业参数的异常处理参数; 2、重构用户定义作业注册方式,通过IJobDefinitionProvider注册; 3、增加IJobActionDefinitionProvider接口,用户可自行注册作业调度后处理程序; 4、增加LINGYUN.Abp.Notifications.Jobs模块,使通知相关作业独立; 5、增加LINGYUN.Abp.BackgroundTasks.DistributedLocking模块,让用户决定是否使用分布式锁定任务; 6、应用服务层增加作业Action管理接口, 便于从前端快速管理作业Action; 7、应用服务层增加作业定义查询接口, 便于从前端快速绑定作业名称、参数等.pull/620/head
140 changed files with 2966 additions and 417 deletions
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,24 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<None Remove="LINGYUN\Abp\Notifications\Jobs\Localization\Resources\*.json" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<EmbeddedResource Include="LINGYUN\Abp\Notifications\Jobs\Localization\Resources\*.json" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\task-management\LINGYUN.Abp.BackgroundTasks.Abstractions\LINGYUN.Abp.BackgroundTasks.Abstractions.csproj" /> |
|||
<ProjectReference Include="..\LINGYUN.Abp.Notifications\LINGYUN.Abp.Notifications.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,27 @@ |
|||
using LINGYUN.Abp.BackgroundTasks; |
|||
using LINGYUN.Abp.Notifications.Localization; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace LINGYUN.Abp.Notifications.Jobs; |
|||
|
|||
[DependsOn(typeof(AbpNotificationModule))] |
|||
[DependsOn(typeof(AbpBackgroundTasksAbstractionsModule))] |
|||
public class AbpNotificationsJobsModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AbpNotificationsJobsModule>(); |
|||
}); |
|||
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Resources |
|||
.Get<NotificationsResource>() |
|||
.AddVirtualJson("/LINGYUN/Abp/Notifications/Jobs/Localization/Resources"); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using LINGYUN.Abp.Notifications.Localization; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.Notifications.Jobs; |
|||
|
|||
internal static class LocalizableStatic |
|||
{ |
|||
public static ILocalizableString Create(string name) |
|||
{ |
|||
return LocalizableString.Create<NotificationsResource>(name); |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
{ |
|||
"culture": "en", |
|||
"texts": { |
|||
"NotificationCleanupJob": "Notification Cleanup Job", |
|||
"Notification:BatchCount": "Batch Count" |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
{ |
|||
"culture": "zh-Hans", |
|||
"texts": { |
|||
"NotificationCleanupJob": "清理过期通知作业", |
|||
"Notification:BatchCount": "批次数量" |
|||
} |
|||
} |
|||
@ -1,17 +1,26 @@ |
|||
using LINGYUN.Abp.BackgroundTasks; |
|||
using LINGYUN.Abp.Notifications; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LY.MicroService.RealtimeMessage.BackgroundJobs; |
|||
namespace LINGYUN.Abp.Notifications.Jobs; |
|||
|
|||
public class NotificationCleanupJob : IJobRunnable |
|||
{ |
|||
#region Definition Paramters
|
|||
|
|||
public readonly static IReadOnlyList<JobDefinitionParamter> Paramters = |
|||
new List<JobDefinitionParamter> |
|||
{ |
|||
new JobDefinitionParamter(PropertyBatchCount, LocalizableStatic.Create("Notification:BatchCount")) |
|||
}; |
|||
|
|||
#endregion
|
|||
public const string Name = "NotificationCleanupJob"; |
|||
/// <summary>
|
|||
/// 每次清除记录大小
|
|||
/// </summary>
|
|||
public const string PropertyBatchCount = "BatchCount"; |
|||
|
|||
|
|||
public async virtual Task ExecuteAsync(JobRunnableContext context) |
|||
{ |
|||
var count = context.GetJobData<int>(PropertyBatchCount); |
|||
@ -0,0 +1,16 @@ |
|||
using LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
namespace LINGYUN.Abp.Notifications.Jobs; |
|||
|
|||
public class NotificationJobDefinitionProvider : JobDefinitionProvider |
|||
{ |
|||
public override void Define(IJobDefinitionContext context) |
|||
{ |
|||
context.Add( |
|||
new JobDefinition( |
|||
NotificationCleanupJob.Name, |
|||
typeof(NotificationCleanupJob), |
|||
LocalizableStatic.Create("NotificationCleanupJob"), |
|||
NotificationCleanupJob.Paramters)); |
|||
} |
|||
} |
|||
@ -1,7 +1,43 @@ |
|||
using Volo.Abp.Modularity; |
|||
using LINGYUN.Abp.BackgroundTasks.Localization; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
[DependsOn(typeof(AbpLocalizationModule))] |
|||
public class AbpBackgroundTasksAbstractionsModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
AutoAddDefinitionProviders(context.Services); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Resources.Add<BackgroundTasksResource>("en"); |
|||
}); |
|||
} |
|||
|
|||
private static void AutoAddDefinitionProviders(IServiceCollection services) |
|||
{ |
|||
var definitionProviders = new List<Type>(); |
|||
|
|||
services.OnRegistred(context => |
|||
{ |
|||
if (typeof(IJobDefinitionProvider).IsAssignableFrom(context.ImplementationType)) |
|||
{ |
|||
definitionProviders.Add(context.ImplementationType); |
|||
} |
|||
}); |
|||
|
|||
services.Configure<AbpBackgroundTasksOptions>(options => |
|||
{ |
|||
options.DefinitionProviders.AddIfNotContains(definitionProviders); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,8 @@ |
|||
using System; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
[AttributeUsage(AttributeTargets.Class)] |
|||
public class DisableJobActionAttribute : Attribute |
|||
{ |
|||
} |
|||
@ -1,9 +0,0 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
public interface IJobCompletedNotifierProvider |
|||
{ |
|||
Task NotifyComplateAsync([NotNull] JobEventContext context); |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
public interface IJobDefinitionContext |
|||
{ |
|||
JobDefinition GetOrNull(string name); |
|||
|
|||
IReadOnlyList<JobDefinition> GetAll(); |
|||
|
|||
void Add(params JobDefinition[] definitions); |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
public interface IJobDefinitionManager |
|||
{ |
|||
[NotNull] |
|||
JobDefinition Get([NotNull] string name); |
|||
|
|||
IReadOnlyList<JobDefinition> GetAll(); |
|||
|
|||
JobDefinition GetOrNull(string name); |
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
public interface IJobDefinitionProvider |
|||
{ |
|||
void Define(IJobDefinitionContext context); |
|||
} |
|||
@ -1,11 +0,0 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
public interface IJobExecutedNotifier |
|||
{ |
|||
Task NotifyErrorAsync([NotNull] JobEventContext context); |
|||
Task NotifySuccessAsync([NotNull] JobEventContext context); |
|||
Task NotifyComplateAsync([NotNull] JobEventContext context); |
|||
} |
|||
@ -1,9 +0,0 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
public interface IJobFailedNotifierProvider |
|||
{ |
|||
Task NotifyErrorAsync([NotNull] JobEventContext context); |
|||
} |
|||
@ -1,9 +0,0 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
public interface IJobSuccessNotifierProvider |
|||
{ |
|||
Task NotifySuccessAsync([NotNull] JobEventContext context); |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
public enum JobActionType |
|||
{ |
|||
Failed = -1, |
|||
Successed = 0, |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
using JetBrains.Annotations; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
public class JobDefinition |
|||
{ |
|||
/// <summary>
|
|||
/// 名称
|
|||
/// </summary>
|
|||
public string Name { get; } |
|||
/// <summary>
|
|||
/// 作业类型
|
|||
/// </summary>
|
|||
public Type JobType { get; } |
|||
/// <summary>
|
|||
/// 显示名称
|
|||
/// </summary>
|
|||
public ILocalizableString DisplayName { get; } |
|||
/// <summary>
|
|||
/// 描述
|
|||
/// </summary>
|
|||
public ILocalizableString Description { get; } |
|||
/// <summary>
|
|||
/// 参数列表
|
|||
/// </summary>
|
|||
public IReadOnlyList<JobDefinitionParamter> Paramters { get; } |
|||
public JobDefinition( |
|||
[NotNull] string name, |
|||
[NotNull] Type jobType, |
|||
[NotNull] ILocalizableString displayName, |
|||
[CanBeNull] IReadOnlyList<JobDefinitionParamter> paramters = null, |
|||
[CanBeNull] ILocalizableString description = null) |
|||
{ |
|||
Name = name; |
|||
JobType = jobType; |
|||
DisplayName = displayName; |
|||
Description = description; |
|||
Paramters = paramters ?? new JobDefinitionParamter[0]; |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Collections.Immutable; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
public class JobDefinitionContext : IJobDefinitionContext |
|||
{ |
|||
protected Dictionary<string, JobDefinition> Jobs { get; } |
|||
|
|||
public JobDefinitionContext(Dictionary<string, JobDefinition> jobs) |
|||
{ |
|||
Jobs = jobs; |
|||
} |
|||
|
|||
public virtual JobDefinition GetOrNull(string name) |
|||
{ |
|||
return Jobs.GetOrDefault(name); |
|||
} |
|||
|
|||
public virtual IReadOnlyList<JobDefinition> GetAll() |
|||
{ |
|||
return Jobs.Values.ToImmutableList(); |
|||
} |
|||
|
|||
public virtual void Add(params JobDefinition[] definitions) |
|||
{ |
|||
if (definitions.IsNullOrEmpty()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
foreach (var definition in definitions) |
|||
{ |
|||
Jobs[definition.Name] = definition; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,73 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Collections.Immutable; |
|||
using System.Linq; |
|||
using Volo.Abp; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
public class JobDefinitionManager : IJobDefinitionManager, ISingletonDependency |
|||
{ |
|||
protected Lazy<IDictionary<string, JobDefinition>> JobDefinitions { get; } |
|||
|
|||
protected AbpBackgroundTasksOptions Options { get; } |
|||
|
|||
protected IServiceProvider ServiceProvider { get; } |
|||
|
|||
public JobDefinitionManager( |
|||
IOptions<AbpBackgroundTasksOptions> options, |
|||
IServiceProvider serviceProvider) |
|||
{ |
|||
ServiceProvider = serviceProvider; |
|||
Options = options.Value; |
|||
|
|||
JobDefinitions = new Lazy<IDictionary<string, JobDefinition>>(CreateJobDefinitions, true); |
|||
} |
|||
|
|||
public virtual JobDefinition Get(string name) |
|||
{ |
|||
Check.NotNull(name, nameof(name)); |
|||
|
|||
var action = GetOrNull(name); |
|||
|
|||
if (action == null) |
|||
{ |
|||
throw new AbpException("Undefined job: " + name); |
|||
} |
|||
|
|||
return action; |
|||
} |
|||
|
|||
public virtual IReadOnlyList<JobDefinition> GetAll() |
|||
{ |
|||
return JobDefinitions.Value.Values.ToImmutableList(); |
|||
} |
|||
|
|||
public virtual JobDefinition GetOrNull(string name) |
|||
{ |
|||
return JobDefinitions.Value.GetOrDefault(name); |
|||
} |
|||
|
|||
protected virtual IDictionary<string, JobDefinition> CreateJobDefinitions() |
|||
{ |
|||
var jobs = new Dictionary<string, JobDefinition>(); |
|||
|
|||
using (var scope = ServiceProvider.CreateScope()) |
|||
{ |
|||
var providers = Options |
|||
.DefinitionProviders |
|||
.Select(p => scope.ServiceProvider.GetRequiredService(p) as IJobDefinitionProvider) |
|||
.ToList(); |
|||
|
|||
foreach (var provider in providers) |
|||
{ |
|||
provider.Define(new JobDefinitionContext(jobs)); |
|||
} |
|||
} |
|||
|
|||
return jobs; |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
public class JobDefinitionParamter |
|||
{ |
|||
public string Name { get; } |
|||
|
|||
public bool Required { get; } |
|||
|
|||
public ILocalizableString DisplayName { get; } |
|||
|
|||
public ILocalizableString Description { get; } |
|||
|
|||
public JobDefinitionParamter( |
|||
[NotNull] string name, |
|||
[NotNull] ILocalizableString displayName, |
|||
[CanBeNull] ILocalizableString description = null, |
|||
bool required = false) |
|||
{ |
|||
Name = name; |
|||
Required = required; |
|||
DisplayName = displayName; |
|||
Description = description; |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
public abstract class JobDefinitionProvider : IJobDefinitionProvider, ITransientDependency |
|||
{ |
|||
public abstract void Define(IJobDefinitionContext context); |
|||
} |
|||
@ -1,67 +0,0 @@ |
|||
using JetBrains.Annotations; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
public class JobExecutedNotifier : IJobExecutedNotifier, ISingletonDependency |
|||
{ |
|||
public ILogger<JobExecutedNotifier> Logger { protected get; set; } |
|||
|
|||
public JobExecutedNotifier() |
|||
{ |
|||
Logger = NullLogger<JobExecutedNotifier>.Instance; |
|||
} |
|||
|
|||
public async Task NotifyComplateAsync([NotNull] JobEventContext context) |
|||
{ |
|||
var notifier = context.ServiceProvider.GetService<IJobCompletedNotifierProvider>(); |
|||
if (notifier != null) |
|||
{ |
|||
try |
|||
{ |
|||
await notifier.NotifyComplateAsync(context); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Logger.LogWarning($"An exception thow with job complete notify: {ex.Message}"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public async Task NotifyErrorAsync([NotNull] JobEventContext context) |
|||
{ |
|||
var notifier = context.ServiceProvider.GetService<IJobFailedNotifierProvider>(); |
|||
if (notifier != null) |
|||
{ |
|||
try |
|||
{ |
|||
await notifier.NotifyErrorAsync(context); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Logger.LogWarning($"An exception thow with job error notify: {ex.Message}"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public async Task NotifySuccessAsync([NotNull] JobEventContext context) |
|||
{ |
|||
var notifier = context.ServiceProvider.GetService<IJobSuccessNotifierProvider>(); |
|||
if (notifier != null) |
|||
{ |
|||
try |
|||
{ |
|||
await notifier.NotifySuccessAsync(context); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Logger.LogWarning($"An exception thow with job success notify: {ex.Message}"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
# LINGYUN.Abp.BackgroundTasks.Abstractions |
|||
|
|||
后台任务(队列)模块抽象层,定义一些基本构造与接口 |
|||
|
|||
## 特性参数 |
|||
|
|||
* DisableJobActionAttribute 标记此特性不处理作业触发后行为 |
|||
|
|||
## 配置使用 |
|||
|
|||
模块按需引用 |
|||
|
|||
```csharp |
|||
[DependsOn(typeof(AbpBackgroundTasksAbstractionsModule))] |
|||
public class YouProjectModule : AbpModule |
|||
{ |
|||
// other |
|||
} |
|||
``` |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,27 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<None Remove="LINGYUN\Abp\BackgroundTasks\Activities\Localization\Resources\*.json" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<EmbeddedResource Include="LINGYUN\Abp\BackgroundTasks\Activities\Localization\Resources\*.json" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Localization" Version="$(VoloAbpPackageVersion)" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\LINGYUN.Abp.BackgroundTasks.Abstractions\LINGYUN.Abp.BackgroundTasks.Abstractions.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,57 @@ |
|||
using LINGYUN.Abp.BackgroundTasks.Localization; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
[DependsOn(typeof(AbpLocalizationModule))] |
|||
[DependsOn(typeof(AbpBackgroundTasksAbstractionsModule))] |
|||
public class AbpBackgroundTasksActivitiesModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
AutoAddDefinitionProviders(context.Services); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AbpBackgroundTasksActivitiesModule>(); |
|||
}); |
|||
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Resources |
|||
.Get<BackgroundTasksResource>() |
|||
.AddVirtualJson("/LINGYUN/Abp/BackgroundTasks/Activities/Localization/Resources"); |
|||
}); |
|||
|
|||
Configure<AbpBackgroundTasksOptions>(options => |
|||
{ |
|||
options.JobMonitors.AddIfNotContains(typeof(JobActionEvent)); |
|||
}); |
|||
} |
|||
|
|||
private static void AutoAddDefinitionProviders(IServiceCollection services) |
|||
{ |
|||
var definitionProviders = new List<Type>(); |
|||
|
|||
services.OnRegistred(context => |
|||
{ |
|||
if (typeof(IJobActionDefinitionProvider).IsAssignableFrom(context.ImplementationType)) |
|||
{ |
|||
definitionProviders.Add(context.ImplementationType); |
|||
} |
|||
}); |
|||
|
|||
services.Configure<AbpBackgroundTasksActivitiesOptions>(options => |
|||
{ |
|||
options.DefinitionProviders.AddIfNotContains(definitionProviders); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using Volo.Abp.Collections; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
public class AbpBackgroundTasksActivitiesOptions |
|||
{ |
|||
public ITypeList<IJobActionDefinitionProvider> DefinitionProviders { get; } |
|||
|
|||
public AbpBackgroundTasksActivitiesOptions() |
|||
{ |
|||
DefinitionProviders = new TypeList<IJobActionDefinitionProvider>(); |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
[Dependency(TryRegister = true)] |
|||
public class DefaultJobActionStore : IJobActionStore, ISingletonDependency |
|||
{ |
|||
public Task<List<JobAction>> GetActionsAsync(string id, CancellationToken cancellationToken = default) |
|||
{ |
|||
return Task.FromResult(new List<JobAction>()); |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
public interface IJobActionDefinitionContext |
|||
{ |
|||
JobActionDefinition GetOrNull(string name); |
|||
|
|||
IReadOnlyList<JobActionDefinition> GetAll(); |
|||
|
|||
void Add(params JobActionDefinition[] definitions); |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
public interface IJobActionDefinitionManager |
|||
{ |
|||
[NotNull] |
|||
JobActionDefinition Get([NotNull] string name); |
|||
|
|||
IReadOnlyList<JobActionDefinition> GetAll(); |
|||
|
|||
JobActionDefinition GetOrNull(string name); |
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
public interface IJobActionDefinitionProvider |
|||
{ |
|||
void Define(IJobActionDefinitionContext context); |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
public interface IJobActionStore |
|||
{ |
|||
Task<List<JobAction>> GetActionsAsync(string id, CancellationToken cancellationToken = default); |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
public interface IJobExecutedProvider |
|||
{ |
|||
Task NotifyErrorAsync([NotNull] JobActionExecuteContext context); |
|||
Task NotifySuccessAsync([NotNull] JobActionExecuteContext context); |
|||
Task NotifyComplateAsync([NotNull] JobActionExecuteContext context); |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
public class JobAction |
|||
{ |
|||
public string Name { get; set; } |
|||
public Dictionary<string, object> Paramters { get; set; } |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Collections; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
public class JobActionDefinition |
|||
{ |
|||
/// <summary>
|
|||
/// 名称
|
|||
/// </summary>
|
|||
public string Name { get; } |
|||
/// <summary>
|
|||
/// 类型
|
|||
/// </summary>
|
|||
public JobActionType Type { get; } |
|||
/// <summary>
|
|||
/// 显示名称
|
|||
/// </summary>
|
|||
public ILocalizableString DisplayName { get; } |
|||
/// <summary>
|
|||
/// 描述
|
|||
/// </summary>
|
|||
public ILocalizableString Description { get; } |
|||
/// <summary>
|
|||
/// 参数列表
|
|||
/// </summary>
|
|||
public IList<JobActionParamter> Paramters { get; } |
|||
/// <summary>
|
|||
/// 通知提供者
|
|||
/// </summary>
|
|||
public ITypeList<IJobExecutedProvider> Providers { get; } |
|||
public JobActionDefinition( |
|||
[NotNull] string name, |
|||
[NotNull] JobActionType type, |
|||
[NotNull] ILocalizableString displayName, |
|||
[NotNull] IList<JobActionParamter> paramters, |
|||
ILocalizableString description = null) |
|||
{ |
|||
Name = name; |
|||
Type = type; |
|||
DisplayName = displayName; |
|||
Paramters = paramters; |
|||
Description = description; |
|||
|
|||
Providers = new TypeList<IJobExecutedProvider>(); |
|||
} |
|||
|
|||
public virtual JobActionDefinition WithProvider<TProvider>() |
|||
where TProvider : IJobExecutedProvider |
|||
{ |
|||
Providers.Add(typeof(TProvider)); |
|||
|
|||
return this; |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Collections.Immutable; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
public class JobActionDefinitionContext : IJobActionDefinitionContext |
|||
{ |
|||
protected Dictionary<string, JobActionDefinition> Actions { get; } |
|||
|
|||
public JobActionDefinitionContext(Dictionary<string, JobActionDefinition> actions) |
|||
{ |
|||
Actions = actions; |
|||
} |
|||
|
|||
public virtual JobActionDefinition GetOrNull(string name) |
|||
{ |
|||
return Actions.GetOrDefault(name); |
|||
} |
|||
|
|||
public virtual IReadOnlyList<JobActionDefinition> GetAll() |
|||
{ |
|||
return Actions.Values.ToImmutableList(); |
|||
} |
|||
|
|||
public virtual void Add(params JobActionDefinition[] definitions) |
|||
{ |
|||
if (definitions.IsNullOrEmpty()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
foreach (var definition in definitions) |
|||
{ |
|||
Actions[definition.Name] = definition; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,73 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Collections.Immutable; |
|||
using System.Linq; |
|||
using Volo.Abp; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
public class JobActionDefinitionManager : IJobActionDefinitionManager, ISingletonDependency |
|||
{ |
|||
protected Lazy<IDictionary<string, JobActionDefinition>> ActionDefinitions { get; } |
|||
|
|||
protected AbpBackgroundTasksActivitiesOptions Options { get; } |
|||
|
|||
protected IServiceProvider ServiceProvider { get; } |
|||
|
|||
public JobActionDefinitionManager( |
|||
IOptions<AbpBackgroundTasksActivitiesOptions> options, |
|||
IServiceProvider serviceProvider) |
|||
{ |
|||
ServiceProvider = serviceProvider; |
|||
Options = options.Value; |
|||
|
|||
ActionDefinitions = new Lazy<IDictionary<string, JobActionDefinition>>(CreateSettingDefinitions, true); |
|||
} |
|||
|
|||
public virtual JobActionDefinition Get(string name) |
|||
{ |
|||
Check.NotNull(name, nameof(name)); |
|||
|
|||
var action = GetOrNull(name); |
|||
|
|||
if (action == null) |
|||
{ |
|||
throw new AbpException("Undefined action: " + name); |
|||
} |
|||
|
|||
return action; |
|||
} |
|||
|
|||
public virtual IReadOnlyList<JobActionDefinition> GetAll() |
|||
{ |
|||
return ActionDefinitions.Value.Values.ToImmutableList(); |
|||
} |
|||
|
|||
public virtual JobActionDefinition GetOrNull(string name) |
|||
{ |
|||
return ActionDefinitions.Value.GetOrDefault(name); |
|||
} |
|||
|
|||
protected virtual IDictionary<string, JobActionDefinition> CreateSettingDefinitions() |
|||
{ |
|||
var actions = new Dictionary<string, JobActionDefinition>(); |
|||
|
|||
using (var scope = ServiceProvider.CreateScope()) |
|||
{ |
|||
var providers = Options |
|||
.DefinitionProviders |
|||
.Select(p => scope.ServiceProvider.GetRequiredService(p) as IJobActionDefinitionProvider) |
|||
.ToList(); |
|||
|
|||
foreach (var provider in providers) |
|||
{ |
|||
provider.Define(new JobActionDefinitionContext(actions)); |
|||
} |
|||
} |
|||
|
|||
return actions; |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
public abstract class JobActionDefinitionProvider : IJobActionDefinitionProvider, ITransientDependency |
|||
{ |
|||
public abstract void Define(IJobActionDefinitionContext context); |
|||
} |
|||
@ -0,0 +1,89 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Logging; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
public class JobActionEvent : JobEventBase<JobActionEvent>, ITransientDependency |
|||
{ |
|||
protected async override Task OnJobAfterExecutedAsync(JobEventContext context) |
|||
{ |
|||
if (context.EventData.Type.IsDefined(typeof(DisableJobActionAttribute), true)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var actions = await GetJobActions(context); |
|||
if (!actions.Any()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var provider = context.ServiceProvider.GetRequiredService<IJobActionDefinitionManager>(); |
|||
|
|||
foreach (var action in actions) |
|||
{ |
|||
var definition = provider.GetOrNull(action.Name); |
|||
|
|||
if (definition == null) |
|||
{ |
|||
Logger.LogWarning($"Cannot execute job action {definition.Name}, Because it's not registered."); |
|||
continue; |
|||
} |
|||
|
|||
await ExecuteAction(context, definition, action); |
|||
} |
|||
} |
|||
|
|||
private async Task<List<JobAction>> GetJobActions(JobEventContext context) |
|||
{ |
|||
var store = context.ServiceProvider.GetRequiredService<IJobActionStore>(); |
|||
|
|||
return await store.GetActionsAsync(context.EventData.Key); |
|||
} |
|||
|
|||
private async Task ExecuteAction(JobEventContext context, JobActionDefinition actionDefinition, JobAction action) |
|||
{ |
|||
var missingRequiredParams = actionDefinition.Paramters |
|||
.Where(p => p.Required) |
|||
.Where(rp => !action.Paramters.Any(p => string.Equals(rp.Name, p.Key))) |
|||
.Select(rp => rp.Name); |
|||
|
|||
if (missingRequiredParams.Any()) |
|||
{ |
|||
Logger.LogWarning($"Cannot execute job action {actionDefinition.Name}, The required parameters are missing: {missingRequiredParams.JoinAsString(Environment.NewLine)}"); |
|||
return; |
|||
} |
|||
|
|||
var notifierContext = new JobActionExecuteContext(action, context); |
|||
|
|||
foreach (var notifierType in actionDefinition.Providers) |
|||
{ |
|||
if (context.ServiceProvider.GetService(notifierType) is IJobExecutedProvider notifier) |
|||
{ |
|||
if (context.EventData.Exception != null) |
|||
{ |
|||
if (actionDefinition.Type == JobActionType.Failed) |
|||
{ |
|||
await notifier.NotifyErrorAsync(notifierContext); |
|||
Logger.LogInformation($"Executed Failed action with {notifierType.Name} was Successed."); |
|||
} |
|||
continue; |
|||
} |
|||
|
|||
if (actionDefinition.Type == JobActionType.Successed) |
|||
{ |
|||
await notifier.NotifySuccessAsync(notifierContext); |
|||
Logger.LogInformation($"Executed Successed action with {notifierType.Name} was Successed."); |
|||
} |
|||
|
|||
await notifier.NotifyComplateAsync(notifierContext); |
|||
Logger.LogInformation($"Executed Complated action with {notifierType.Name} was Successed."); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
public class JobActionExecuteContext |
|||
{ |
|||
public JobAction Action { get; } |
|||
public JobEventContext Event { get; } |
|||
public JobActionExecuteContext( |
|||
[NotNull] JobAction action, |
|||
[NotNull] JobEventContext @event) |
|||
{ |
|||
Action = action; |
|||
Event = @event; |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
public class JobActionParamter |
|||
{ |
|||
public string Name { get; set; } |
|||
public bool Required { get; set; } |
|||
public ILocalizableString DisplayName { get; set; } |
|||
public ILocalizableString Description { get; set; } |
|||
|
|||
public JobActionParamter( |
|||
[NotNull] string name, |
|||
[NotNull] ILocalizableString displayName, |
|||
[CanBeNull] ILocalizableString description = null, |
|||
bool required = false) |
|||
{ |
|||
Name = name; |
|||
DisplayName = displayName; |
|||
Description = description; |
|||
Required = required; |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Activities; |
|||
|
|||
public abstract class JobExecutedProvider : IJobExecutedProvider |
|||
{ |
|||
public virtual Task NotifyComplateAsync([NotNull] JobActionExecuteContext context) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
public virtual Task NotifyErrorAsync([NotNull] JobActionExecuteContext context) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
public virtual Task NotifySuccessAsync([NotNull] JobActionExecuteContext context) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
{ |
|||
"culture": "en", |
|||
"texts": { |
|||
} |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
{ |
|||
"culture": "zh-Hans", |
|||
"texts": { |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
# LINGYUN.Abp.BackgroundTasks.Activities |
|||
|
|||
后台任务(队列)模块行为处理模块 |
|||
|
|||
## 接口参数 |
|||
|
|||
* IJobActionStore 实现此接口获取作业管理行为 |
|||
* JobActionDefinitionProvider 实现此接口自定义作业行为 |
|||
* JobExecutedProvider 实现此接口扩展作业行为 |
|||
|
|||
## 配置使用 |
|||
|
|||
模块按需引用 |
|||
|
|||
```csharp |
|||
[DependsOn(typeof(AbpBackgroundTasksActivitiesModule))] |
|||
public class YouProjectModule : AbpModule |
|||
{ |
|||
// other |
|||
} |
|||
``` |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,19 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.DistributedLocking.Abstractions" Version="$(VoloAbpPackageVersion)" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\LINGYUN.Abp.BackgroundTasks\LINGYUN.Abp.BackgroundTasks.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,11 @@ |
|||
using Volo.Abp.DistributedLocking; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.DistributedLocking; |
|||
|
|||
[DependsOn(typeof(AbpBackgroundTasksModule))] |
|||
[DependsOn(typeof(AbpDistributedLockingAbstractionsModule))] |
|||
public class AbpBackgroundTasksDistributedLockingModule : AbpModule |
|||
{ |
|||
|
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
# LINGYUN.Abp.BackgroundTasks.DistributedLocking |
|||
|
|||
后台任务(队列)模块分布式锁模块 |
|||
|
|||
See: [Distributed-Locking](https://docs.abp.io/en/abp/latest/Distributed-Locking) |
|||
|
|||
## 配置使用 |
|||
|
|||
模块按需引用 |
|||
|
|||
```csharp |
|||
[DependsOn(typeof(AbpBackgroundTasksDistributedLockingModule))] |
|||
public class YouProjectModule : AbpModule |
|||
{ |
|||
// other |
|||
} |
|||
``` |
|||
@ -0,0 +1,15 @@ |
|||
# LINGYUN.Abp.BackgroundTasks.EventBus |
|||
|
|||
后台任务(队列)模块分布式事件模块,集成模块使应用程序具备处理作业事件能力 |
|||
|
|||
## 配置使用 |
|||
|
|||
模块按需引用 |
|||
|
|||
```csharp |
|||
[DependsOn(typeof(AbpBackgroundTasksEventBusModule))] |
|||
public class YouProjectModule : AbpModule |
|||
{ |
|||
// other |
|||
} |
|||
``` |
|||
@ -0,0 +1,25 @@ |
|||
using LINGYUN.Abp.BackgroundTasks.Activities; |
|||
using LINGYUN.Abp.BackgroundTasks.Localization; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.ExceptionHandling; |
|||
|
|||
public class ExceptionHandlingJobActionDefinitionProvider : JobActionDefinitionProvider |
|||
{ |
|||
public override void Define(IJobActionDefinitionContext context) |
|||
{ |
|||
context.Add( |
|||
new JobActionDefinition( |
|||
JobExecutedFailedProvider.Name, |
|||
JobActionType.Failed, |
|||
L("JobExceptionNotifier"), |
|||
JobExecutedFailedProvider.Paramters, |
|||
L("JobExceptionNotifier")) |
|||
.WithProvider<JobExecutedFailedProvider>()); |
|||
} |
|||
|
|||
private static ILocalizableString L(string name) |
|||
{ |
|||
return LocalizableString.Create<BackgroundTasksResource>(name); |
|||
} |
|||
} |
|||
@ -0,0 +1,144 @@ |
|||
using JetBrains.Annotations; |
|||
using LINGYUN.Abp.BackgroundTasks.Activities; |
|||
using LINGYUN.Abp.BackgroundTasks.ExceptionHandling.Templates; |
|||
using LINGYUN.Abp.BackgroundTasks.Localization; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Globalization; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Emailing; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.TextTemplating; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.ExceptionHandling; |
|||
|
|||
public class JobExecutedFailedProvider : JobExecutedProvider, ITransientDependency |
|||
{ |
|||
public const string Name = "JobExecutedFailedProvider"; |
|||
public readonly static IList<JobActionParamter> Paramters = new List<JobActionParamter> |
|||
{ |
|||
new JobActionParamter(PropertyTo, L("DisplayName:PropertyTo"), L("Description:PropertyTo"), true), |
|||
|
|||
new JobActionParamter(PropertySubject, L("DisplayName:PropertySubject"), L("Description:PropertySubject")), |
|||
new JobActionParamter(PropertyFrom, L("DisplayName:PropertyFrom"), L("Description:PropertyFrom")), |
|||
new JobActionParamter(PropertyBody, L("DisplayName:PropertyBody"), L("Description:PropertyBody")), |
|||
new JobActionParamter(PropertyTemplate, L("DisplayName:PropertyTemplate"), L("Description:PropertyTemplate")), |
|||
new JobActionParamter(PropertyContext, L("DisplayName:PropertyContext"), L("Description:PropertyContext")), |
|||
new JobActionParamter(PropertyCulture, L("DisplayName:PropertyCulture"), L("Description:PropertyCulture")), |
|||
}; |
|||
|
|||
public const string Prefix = "exception."; |
|||
public const string JobGroup = "ExceptionNotifier"; |
|||
|
|||
public const string PropertyFrom = Prefix + "from"; |
|||
/// <summary>
|
|||
/// 接收者
|
|||
/// </summary>
|
|||
public const string PropertyTo = Prefix + "to"; |
|||
/// <summary>
|
|||
/// 必须,邮件主体
|
|||
/// </summary>
|
|||
public const string PropertySubject = Prefix + "subject"; |
|||
/// <summary>
|
|||
/// 消息内容, 文本消息时必须
|
|||
/// </summary>
|
|||
public const string PropertyBody = Prefix + "body"; |
|||
/// <summary>
|
|||
/// 发送模板消息
|
|||
/// </summary>
|
|||
public const string PropertyTemplate = Prefix + "template"; |
|||
/// <summary>
|
|||
/// 可选, 模板消息中的上下文参数
|
|||
/// </summary>
|
|||
public const string PropertyContext = Prefix + "context"; |
|||
/// <summary>
|
|||
/// 可选, 模板消息中的区域性
|
|||
/// </summary>
|
|||
public const string PropertyCulture = Prefix + "culture"; |
|||
|
|||
public ILogger<JobExecutedFailedProvider> Logger { protected get; set; } |
|||
|
|||
protected IEmailSender EmailSender { get; } |
|||
protected ITemplateRenderer TemplateRenderer { get; } |
|||
public JobExecutedFailedProvider( |
|||
IEmailSender emailSender, |
|||
ITemplateRenderer templateRenderer) |
|||
{ |
|||
EmailSender = emailSender; |
|||
TemplateRenderer = templateRenderer; |
|||
|
|||
Logger = NullLogger<JobExecutedFailedProvider>.Instance; |
|||
} |
|||
|
|||
public override async Task NotifyErrorAsync([NotNull] JobActionExecuteContext context) |
|||
{ |
|||
if (context.Action.Paramters.TryGetValue(PropertyTo, out var exceptionTo) && |
|||
exceptionTo is string to) |
|||
{ |
|||
var template = context.Action.Paramters.GetOrDefault(PropertyTemplate)?.ToString() ?? ""; |
|||
var subject = context.Action.Paramters.GetOrDefault(PropertySubject)?.ToString() ?? "From job execute exception"; |
|||
var from = context.Action.Paramters.GetOrDefault(PropertyFrom)?.ToString() ?? ""; |
|||
var errorMessage = context.Event.EventData.Exception.GetBaseException().Message; |
|||
|
|||
if (template.IsNullOrWhiteSpace()) |
|||
{ |
|||
// var message = eventData.Args.GetOrDefault(SendEmailJob.PropertyBody)?.ToString() ?? "";
|
|||
// await EmailSender.SendAsync(from, to, subject, message, false);
|
|||
// return;
|
|||
// 默认使用内置模板发送错误
|
|||
template = JobExceptionHandlingTemplates.JobExceptionNotifier; |
|||
} |
|||
|
|||
var footer = context.Action.Paramters.GetOrDefault("footer")?.ToString() ?? $"Copyright to LY Colin © {context.Event.EventData.RunTime.Year}"; |
|||
var model = new |
|||
{ |
|||
Title = subject, |
|||
Id = context.Event.EventData.Key, |
|||
Group = context.Action.Paramters.GetOrDefault(nameof(JobInfo.Group)) ?? context.Event.EventData.Group, |
|||
Name = context.Action.Paramters.GetOrDefault(nameof(JobInfo.Name)) ?? context.Event.EventData.Name, |
|||
Type = context.Action.Paramters.GetOrDefault(nameof(JobInfo.Type)) ?? context.Event.EventData.Type.Name, |
|||
Triggertime = context.Event.EventData.RunTime.ToString("yyyy-MM-dd HH:mm:ss"), |
|||
Message = errorMessage, |
|||
Tenantname = context.Action.Paramters.GetOrDefault(nameof(IMultiTenant.TenantId)), |
|||
Footer = footer, |
|||
}; |
|||
|
|||
var globalContext = new Dictionary<string, object>(); |
|||
if (context.Action.Paramters.TryGetValue(PropertyContext, out var ctx) && |
|||
ctx is string ctxStr && !ctxStr.IsNullOrWhiteSpace()) |
|||
{ |
|||
try |
|||
{ |
|||
globalContext = JsonConvert.DeserializeObject<Dictionary<string, object>>(ctxStr); |
|||
} |
|||
catch { } |
|||
} |
|||
globalContext.AddIfNotContains(context.Action.Paramters); |
|||
|
|||
var culture = context.Action.Paramters.GetOrDefault(PropertyCulture)?.ToString() ?? CultureInfo.CurrentCulture.Name; |
|||
|
|||
var content = await TemplateRenderer.RenderAsync( |
|||
templateName: template, |
|||
model: model, |
|||
cultureName: culture, |
|||
globalContext: globalContext); |
|||
|
|||
if (from.IsNullOrWhiteSpace()) |
|||
{ |
|||
await EmailSender.SendAsync(to, subject, content, true); |
|||
return; |
|||
} |
|||
await EmailSender.SendAsync(from, to, subject, content, true); |
|||
} |
|||
} |
|||
|
|||
private static ILocalizableString L(string name) |
|||
{ |
|||
return LocalizableString.Create<BackgroundTasksResource>(name); |
|||
} |
|||
} |
|||
@ -1,132 +0,0 @@ |
|||
using JetBrains.Annotations; |
|||
using LINGYUN.Abp.BackgroundTasks.ExceptionHandling.Templates; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Globalization; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Emailing; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.TextTemplating; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.ExceptionHandling; |
|||
|
|||
public class JobFailedNotifierProvider : IJobFailedNotifierProvider, ITransientDependency |
|||
{ |
|||
public const string Prefix = "exception."; |
|||
public const string JobGroup = "ExceptionNotifier"; |
|||
|
|||
public const string PropertyFrom = "from"; |
|||
/// <summary>
|
|||
/// 接收者
|
|||
/// </summary>
|
|||
public const string PropertyTo = "to"; |
|||
/// <summary>
|
|||
/// 必须,邮件主体
|
|||
/// </summary>
|
|||
public const string PropertySubject = "subject"; |
|||
/// <summary>
|
|||
/// 消息内容, 文本消息时必须
|
|||
/// </summary>
|
|||
public const string PropertyBody = "body"; |
|||
/// <summary>
|
|||
/// 发送模板消息
|
|||
/// </summary>
|
|||
public const string PropertyTemplate = "template"; |
|||
/// <summary>
|
|||
/// 可选, 模板消息中的上下文参数
|
|||
/// </summary>
|
|||
public const string PropertyContext = "context"; |
|||
/// <summary>
|
|||
/// 可选, 模板消息中的区域性
|
|||
/// </summary>
|
|||
public const string PropertyCulture = "culture"; |
|||
|
|||
public ILogger<JobFailedNotifierProvider> Logger { protected get; set; } |
|||
|
|||
protected IEmailSender EmailSender { get; } |
|||
protected ITemplateRenderer TemplateRenderer { get; } |
|||
|
|||
public JobFailedNotifierProvider( |
|||
IEmailSender emailSender, |
|||
ITemplateRenderer templateRenderer) |
|||
{ |
|||
EmailSender = emailSender; |
|||
TemplateRenderer = templateRenderer; |
|||
|
|||
Logger = NullLogger<JobFailedNotifierProvider>.Instance; |
|||
} |
|||
|
|||
public virtual async Task NotifyErrorAsync([NotNull] JobEventContext context) |
|||
{ |
|||
var eventData = context.EventData; |
|||
// 异常所属分组不处理, 防止死循环
|
|||
if (string.Equals(eventData.Group, JobGroup)) |
|||
{ |
|||
Logger.LogWarning($"There is a problem executing the job, reason: {eventData.Exception.Message}"); |
|||
return; |
|||
} |
|||
var notifyKey = Prefix + PropertyTo; |
|||
if (eventData.Args.TryGetValue(notifyKey, out var exceptionTo) && |
|||
exceptionTo is string to) |
|||
{ |
|||
var template = eventData.Args.GetOrDefault(Prefix + PropertyTemplate)?.ToString() ?? ""; |
|||
var subject = eventData.Args.GetOrDefault(Prefix + PropertySubject)?.ToString() ?? "From job execute exception"; |
|||
var from = eventData.Args.GetOrDefault(Prefix + PropertyFrom)?.ToString() ?? ""; |
|||
var errorMessage = eventData.Exception.GetBaseException().Message; |
|||
|
|||
if (template.IsNullOrWhiteSpace()) |
|||
{ |
|||
// var message = eventData.Args.GetOrDefault(Prefix + SendEmailJob.PropertyBody)?.ToString() ?? "";
|
|||
// await EmailSender.SendAsync(from, to, subject, message, false);
|
|||
// return;
|
|||
// 默认使用内置模板发送错误
|
|||
template = JobExceptionHandlingTemplates.JobExceptionNotifier; |
|||
} |
|||
|
|||
var footer = eventData.Args.GetOrDefault("footer")?.ToString() ?? $"Copyright to LY Colin © {eventData.RunTime.Year}"; |
|||
var model = new |
|||
{ |
|||
Title = subject, |
|||
Id = eventData.Key, |
|||
Group = eventData.Args.GetOrDefault(nameof(JobInfo.Group)) ?? eventData.Group, |
|||
Name = eventData.Args.GetOrDefault(nameof(JobInfo.Name)) ?? eventData.Name, |
|||
Type = eventData.Args.GetOrDefault(nameof(JobInfo.Type)) ?? eventData.Type.Name, |
|||
Triggertime = eventData.RunTime.ToString("yyyy-MM-dd HH:mm:ss"), |
|||
Message = errorMessage, |
|||
Tenantname = eventData.Args.GetOrDefault(nameof(IMultiTenant.TenantId)), |
|||
Footer = footer, |
|||
}; |
|||
|
|||
var globalContext = new Dictionary<string, object>(); |
|||
if (eventData.Args.TryGetValue(Prefix + PropertyContext, out var ctx) && |
|||
ctx is string ctxStr && !ctxStr.IsNullOrWhiteSpace()) |
|||
{ |
|||
try |
|||
{ |
|||
globalContext = JsonConvert.DeserializeObject<Dictionary<string, object>>(ctxStr); |
|||
} |
|||
catch { } |
|||
} |
|||
globalContext.AddIfNotContains(eventData.Args); |
|||
|
|||
var culture = eventData.Args.GetOrDefault(Prefix + PropertyCulture)?.ToString() ?? CultureInfo.CurrentCulture.Name; |
|||
|
|||
var content = await TemplateRenderer.RenderAsync( |
|||
templateName: template, |
|||
model: model, |
|||
cultureName: culture, |
|||
globalContext: globalContext); |
|||
|
|||
if (from.IsNullOrWhiteSpace()) |
|||
{ |
|||
await EmailSender.SendAsync(to, subject, content, true); |
|||
return; |
|||
} |
|||
await EmailSender.SendAsync(from, to, subject, content, true); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
namespace LINGYUN.Abp.BackgroundTasks.Jobs; |
|||
|
|||
public class DefaultJobDefinitionProvider : JobDefinitionProvider |
|||
{ |
|||
public override void Define(IJobDefinitionContext context) |
|||
{ |
|||
context.Add(CreateDefaultJobs()); |
|||
} |
|||
|
|||
private static JobDefinition[] CreateDefaultJobs() |
|||
{ |
|||
return new[] |
|||
{ |
|||
new JobDefinition( |
|||
DefaultJobNames.SleepJob, |
|||
typeof(SleepJob), |
|||
LocalizableStatic.Create("SleepJob"), |
|||
SleepJob.Paramters), |
|||
|
|||
new JobDefinition( |
|||
DefaultJobNames.ConsoleJob, |
|||
typeof(ConsoleJob), |
|||
LocalizableStatic.Create("ConsoleJob"), |
|||
ConsoleJob.Paramters), |
|||
|
|||
new JobDefinition( |
|||
DefaultJobNames.SendSmsJob, |
|||
typeof(SendSmsJob), |
|||
LocalizableStatic.Create("SendSmsJob"), |
|||
SendSmsJob.Paramters), |
|||
|
|||
new JobDefinition( |
|||
DefaultJobNames.SendEmailJob, |
|||
typeof(SendEmailJob), |
|||
LocalizableStatic.Create("SendEmailJob"), |
|||
SendEmailJob.Paramters), |
|||
|
|||
new JobDefinition( |
|||
DefaultJobNames.HttpRequestJob, |
|||
typeof(HttpRequestJob), |
|||
LocalizableStatic.Create("HttpRequestJob"), |
|||
HttpRequestJob.Paramters), |
|||
|
|||
new JobDefinition( |
|||
DefaultJobNames.ServiceInvocationJob, |
|||
typeof(ServiceInvocationJob), |
|||
LocalizableStatic.Create("ServiceInvocationJob"), |
|||
ServiceInvocationJob.Paramters), |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using LINGYUN.Abp.BackgroundTasks.Localization; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Jobs; |
|||
|
|||
internal static class LocalizableStatic |
|||
{ |
|||
public static ILocalizableString Create(string name) |
|||
{ |
|||
return LocalizableString.Create<BackgroundTasksResource>(name); |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
{ |
|||
"culture": "en", |
|||
"texts": { |
|||
"SleepJob": "Sleep Job", |
|||
"ConsoleJob": "Console Job", |
|||
"SendSmsJob": "Sms Job", |
|||
"SendEmailJob": "Email Job", |
|||
"HttpRequestJob": "Http Request Job", |
|||
"ServiceInvocationJob": "Service Invocation Job", |
|||
"Console:Message": "Message", |
|||
"Http:Url": "Url", |
|||
"Http:Method": "Method", |
|||
"Http:MethodDesc": "The request method can be GET, PUT, POST, PATCH, OPTIONS, or DELETE.", |
|||
"Http:Data": "Data", |
|||
"Http:ContentType": "Content Type", |
|||
"Http:Headers": "Headers", |
|||
"Http:Culture": "Culture", |
|||
"Http:Service": "Service", |
|||
"Http:Tenant": "Tenant", |
|||
"Http:Provider": "Provider", |
|||
"Http:ProviderDesc": "Interservice invocation program, optional scope: http、dapr.", |
|||
"Http:AppId": "App Id", |
|||
"Http:AppIdDesc": "App Id, This parameter takes effect only when the provider is dapr.", |
|||
"Sms:PhoneNumber": "Phone Number", |
|||
"Sms:Message": "Message", |
|||
"Sms:Properties": "Properties", |
|||
"Emailing:To": "To", |
|||
"Emailing:Subject": "Subject", |
|||
"Emailing:From": "From", |
|||
"Emailing:Body": "Body", |
|||
"Emailing:Template": "Template", |
|||
"Emailing:Model": "Model", |
|||
"Emailing:Context": "Context", |
|||
"Emailing:Culture": "Culture", |
|||
"Sleep:Delay": "Delay(ms)" |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
{ |
|||
"culture": "zh-Hans", |
|||
"texts": { |
|||
"SleepJob": "休眠作业", |
|||
"ConsoleJob": "控制台作业", |
|||
"SendSmsJob": "短信作业", |
|||
"SendEmailJob": "邮件作业", |
|||
"HttpRequestJob": "Http请求作业", |
|||
"ServiceInvocationJob": "远程调用作业", |
|||
"Console:Message": "消息", |
|||
"Http:Url": "请求路径", |
|||
"Http:Method": "请求方法", |
|||
"Http:MethodDesc": "请求方法,支持的格式为GET、PUT、POST、PATCH、OPTIONS、DELETE.", |
|||
"Http:Data": "传输数据", |
|||
"Http:ContentType": "内容类型", |
|||
"Http:Headers": "请求头", |
|||
"Http:Culture": "文化名称", |
|||
"Http:Service": "服务名称", |
|||
"Http:Tenant": "租户", |
|||
"Http:Provider": "调用方", |
|||
"Http:ProviderDesc": "服务间调用程序,可选范围: http、dapr.", |
|||
"Http:AppId": "应用标识", |
|||
"Http:AppIdDesc": "应用标识,仅限调用方为dapr时生效.", |
|||
"Sms:PhoneNumber": "手机号码", |
|||
"Sms:Message": "消息内容", |
|||
"Sms:Properties": "消息参数", |
|||
"Emailing:To": "收件地址", |
|||
"Emailing:Subject": "邮件标题", |
|||
"Emailing:From": "发送方名称", |
|||
"Emailing:Body": "发送内容", |
|||
"Emailing:Template": "邮件模板", |
|||
"Emailing:Model": "数据", |
|||
"Emailing:Context": "全局参数", |
|||
"Emailing:Culture": "文化名称", |
|||
"Sleep:Delay": "延迟(ms)" |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
# LINGYUN.Abp.BackgroundTasks.Jobs |
|||
|
|||
后台任务(队列)常用作业模块 |
|||
|
|||
## 作业列表 |
|||
|
|||
* [ConsoleJob](./LINGYUN/Abp/BackgroundTasks/Jobs/ConsoleJob): 控制台输出 |
|||
* [HttpRequestJob](./LINGYUN/Abp/BackgroundTasks/Jobs/HttpRequestJob): Http请求 |
|||
* [SendEmailJob](./LINGYUN/Abp/BackgroundTasks/Jobs/SendEmailJob): 发送邮件 |
|||
* [SendSmsJob](./LINGYUN/Abp/BackgroundTasks/Jobs/SendSmsJob): 发送短信 |
|||
* [ServiceInvocationJob](./LINGYUN/Abp/BackgroundTasks/Jobs/ServiceInvocationJob): 服务间调用(Http请求的扩展) |
|||
* [SleepJob](./LINGYUN/Abp/BackgroundTasks/Jobs/SleepJob): 休眠,使作业延期执行 |
|||
|
|||
## 配置使用 |
|||
|
|||
模块按需引用 |
|||
|
|||
```csharp |
|||
[DependsOn(typeof(AbpBackgroundTasksJobsModule))] |
|||
public class YouProjectModule : AbpModule |
|||
{ |
|||
// other |
|||
} |
|||
``` |
|||
@ -1,47 +1,51 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Microsoft.Extensions.Options; |
|||
using Quartz; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Timing; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Quartz; |
|||
|
|||
public class QuartzJobExecutorProvider : IQuartzJobExecutorProvider, ISingletonDependency |
|||
public class QuartzJobCreator : IQuartzJobCreator, ISingletonDependency |
|||
{ |
|||
public ILogger<QuartzJobExecutorProvider> Logger { protected get; set; } |
|||
public ILogger<QuartzJobCreator> Logger { protected get; set; } |
|||
|
|||
protected IClock Clock { get; } |
|||
protected AbpBackgroundTasksOptions Options { get; } |
|||
protected IQuartzKeyBuilder KeyBuilder { get; } |
|||
public QuartzJobExecutorProvider( |
|||
protected IJobDefinitionManager JobDefinitionManager { get; } |
|||
public QuartzJobCreator( |
|||
IClock clock, |
|||
IQuartzKeyBuilder keyBuilder, |
|||
IOptions<AbpBackgroundTasksOptions> options) |
|||
IJobDefinitionManager jobDefinitionManager) |
|||
{ |
|||
Clock = clock; |
|||
Options = options.Value; |
|||
KeyBuilder = keyBuilder; |
|||
JobDefinitionManager = jobDefinitionManager; |
|||
|
|||
Logger = NullLogger<QuartzJobExecutorProvider>.Instance; |
|||
Logger = NullLogger<QuartzJobCreator>.Instance; |
|||
} |
|||
|
|||
public IJobDetail CreateJob(JobInfo job) |
|||
{ |
|||
var jobType = Options.JobProviders.GetOrDefault(job.Type) ?? Type.GetType(job.Type); |
|||
var jobDefinition = JobDefinitionManager.GetOrNull(job.Type); |
|||
var jobType = jobDefinition?.JobType ?? Type.GetType(job.Type); |
|||
if (jobType == null) |
|||
{ |
|||
Logger.LogWarning($"The task: {job.Group} - {job.Name}: {job.Type} is not registered and cannot create an instance of the performer type."); |
|||
return null; |
|||
} |
|||
//Logger.LogWarning($"The task: {job.Group} - {job.Name}: {job.Type} is not registered and cannot create an instance of the performer type.");
|
|||
//return null;
|
|||
|
|||
// 运行时搜寻本地作业
|
|||
jobType = typeof(QuartzJobSearchJobAdapter); |
|||
} |
|||
else |
|||
{ |
|||
if (!typeof(IJob).IsAssignableFrom(jobType)) |
|||
{ |
|||
var adapterType = typeof(QuartzJobSimpleAdapter<>); |
|||
jobType = adapterType.MakeGenericType(jobType); |
|||
} |
|||
} |
|||
|
|||
// 改为 JobId作为名称
|
|||
var jobBuilder = JobBuilder.Create(jobType) |
|||
@ -0,0 +1,40 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Quartz; |
|||
using System.Collections.Immutable; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Quartz; |
|||
|
|||
public class QuartzJobSearchJobAdapter : IJob |
|||
{ |
|||
protected IServiceScopeFactory ServiceScopeFactory { get; } |
|||
protected IJobDefinitionManager JobDefinitionManager { get; } |
|||
|
|||
public QuartzJobSearchJobAdapter( |
|||
IServiceScopeFactory serviceScopeFactory, |
|||
IJobDefinitionManager jobDefinitionManager) |
|||
{ |
|||
ServiceScopeFactory = serviceScopeFactory; |
|||
JobDefinitionManager = jobDefinitionManager; |
|||
} |
|||
|
|||
public async virtual Task Execute(IJobExecutionContext context) |
|||
{ |
|||
var jobType = context.MergedJobDataMap.GetString(nameof(JobInfo.Type)); |
|||
var jobDefinition = JobDefinitionManager.Get(jobType); |
|||
|
|||
using var scope = ServiceScopeFactory.CreateScope(); |
|||
var jobExecuter = scope.ServiceProvider.GetRequiredService<IJobRunnableExecuter>(); |
|||
|
|||
var jobContext = new JobRunnableContext( |
|||
jobDefinition.JobType, |
|||
scope.ServiceProvider, |
|||
context.MergedJobDataMap.ToImmutableDictionary(), |
|||
getCache: (key) => context.Get(key), |
|||
setCache: context.Put); |
|||
|
|||
await jobExecuter.ExecuteAsync(jobContext); |
|||
|
|||
context.Result = jobContext.Result; |
|||
} |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Logging; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.BackgroundTasks.Internal; |
|||
|
|||
public class JobNotifierEvent : JobEventBase<JobNotifierEvent>, ITransientDependency |
|||
{ |
|||
protected async override Task OnJobAfterExecutedAsync(JobEventContext context) |
|||
{ |
|||
try |
|||
{ |
|||
var notifier = context.ServiceProvider.GetRequiredService<IJobExecutedNotifier>(); |
|||
if (context.EventData.Exception != null) |
|||
{ |
|||
await notifier.NotifyErrorAsync(context); |
|||
} |
|||
else |
|||
{ |
|||
await notifier.NotifySuccessAsync(context); |
|||
} |
|||
|
|||
await notifier.NotifyComplateAsync(context); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Logger.LogWarning($"An exception thow with job notify: {ex.Message}"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LINGYUN.Abp.TaskManagement; |
|||
|
|||
public class BackgroundJobActionCreateDto : BackgroundJobActionCreateOrUpdateDto |
|||
{ |
|||
/// <summary>
|
|||
/// 名称
|
|||
/// </summary>
|
|||
[Required] |
|||
[DynamicStringLength(typeof(BackgroundJobActionConsts), nameof(BackgroundJobActionConsts.MaxNameLength))] |
|||
public string Name { get; set; } |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using Volo.Abp.Data; |
|||
|
|||
namespace LINGYUN.Abp.TaskManagement; |
|||
|
|||
public abstract class BackgroundJobActionCreateOrUpdateDto |
|||
{ |
|||
/// <summary>
|
|||
/// 是否启用
|
|||
/// </summary>
|
|||
public bool IsEnabled { get; set; } |
|||
/// <summary>
|
|||
/// 参数
|
|||
/// </summary>
|
|||
public ExtraPropertyDictionary Paramters { get; set; } |
|||
|
|||
public BackgroundJobActionCreateOrUpdateDto() |
|||
{ |
|||
Paramters = new ExtraPropertyDictionary(); |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
using LINGYUN.Abp.BackgroundTasks; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.TaskManagement; |
|||
|
|||
public class BackgroundJobActionDefinitionDto |
|||
{ |
|||
/// <summary>
|
|||
/// 名称
|
|||
/// </summary>
|
|||
public string Name { get; set; } |
|||
/// <summary>
|
|||
/// 类型
|
|||
/// </summary>
|
|||
public JobActionType Type { get; set; } |
|||
/// <summary>
|
|||
/// 显示名称
|
|||
/// </summary>
|
|||
public string DisplayName { get; set; } |
|||
/// <summary>
|
|||
/// 描述
|
|||
/// </summary>
|
|||
public string Description { get; set; } |
|||
/// <summary>
|
|||
/// 参数列表
|
|||
/// </summary>
|
|||
public IList<BackgroundJobActionParamterDto> Paramters { get; set; } |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
using System; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Data; |
|||
|
|||
namespace LINGYUN.Abp.TaskManagement; |
|||
|
|||
public class BackgroundJobActionDto : EntityDto<Guid> |
|||
{ |
|||
/// <summary>
|
|||
/// 作业标识
|
|||
/// </summary>
|
|||
public string JobId { get; set; } |
|||
/// <summary>
|
|||
/// 名称
|
|||
/// </summary>
|
|||
public string Name { get; set; } |
|||
/// <summary>
|
|||
/// 是否启用
|
|||
/// </summary>
|
|||
public bool IsEnabled { get; set; } |
|||
/// <summary>
|
|||
/// 参数
|
|||
/// </summary>
|
|||
public ExtraPropertyDictionary Paramters { get; set; } |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
using LINGYUN.Abp.BackgroundTasks; |
|||
|
|||
namespace LINGYUN.Abp.TaskManagement; |
|||
|
|||
public class BackgroundJobActionGetDefinitionsInput |
|||
{ |
|||
public JobActionType? Type { get; set; } |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
namespace LINGYUN.Abp.TaskManagement; |
|||
|
|||
public class BackgroundJobActionParamterDto |
|||
{ |
|||
public string Name { get; set; } |
|||
public bool Required { get; set; } |
|||
public string DisplayName { get; set; } |
|||
public string Description { get; set; } |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue