diff --git a/aspnet-core/LINGYUN.MicroService.TaskManagement.sln b/aspnet-core/LINGYUN.MicroService.TaskManagement.sln index 0ae43b0bb..1691e1e80 100644 --- a/aspnet-core/LINGYUN.MicroService.TaskManagement.sln +++ b/aspnet-core/LINGYUN.MicroService.TaskManagement.sln @@ -36,6 +36,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LY.MicroService.TaskManagem EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.BackgroundTasks.Abstractions", "modules\task-management\LINGYUN.Abp.BackgroundTasks.Abstractions\LINGYUN.Abp.BackgroundTasks.Abstractions.csproj", "{4A049C32-55F2-4A5F-954A-C8A977C2D87F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.BackgroundTasks.Jobs", "modules\task-management\LINGYUN.Abp.BackgroundTasks.Jobs\LINGYUN.Abp.BackgroundTasks.Jobs.csproj", "{4C59F590-AA6C-4C46-8060-DA65D8305980}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -82,6 +84,10 @@ Global {4A049C32-55F2-4A5F-954A-C8A977C2D87F}.Debug|Any CPU.Build.0 = Debug|Any CPU {4A049C32-55F2-4A5F-954A-C8A977C2D87F}.Release|Any CPU.ActiveCfg = Release|Any CPU {4A049C32-55F2-4A5F-954A-C8A977C2D87F}.Release|Any CPU.Build.0 = Release|Any CPU + {4C59F590-AA6C-4C46-8060-DA65D8305980}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C59F590-AA6C-4C46-8060-DA65D8305980}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C59F590-AA6C-4C46-8060-DA65D8305980}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C59F590-AA6C-4C46-8060-DA65D8305980}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -97,6 +103,7 @@ Global {7051C251-11D0-4971-B13E-F6929AE6DE89} = {385578CC-C0F1-4377-A7A2-682B8F416234} {E8022994-A19F-4540-B9D1-7EF4AA85D18A} = {8DA8A2EE-0B26-487E-A6C4-518906E92B1B} {4A049C32-55F2-4A5F-954A-C8A977C2D87F} = {C38EB7EF-BAE9-4129-862A-71C652B81775} + {4C59F590-AA6C-4C46-8060-DA65D8305980} = {C38EB7EF-BAE9-4129-862A-71C652B81775} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E1FD1F4C-D344-408B-97CF-B6F1F6D7D293} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTaskConcurrentException.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTaskConcurrentException.cs index a4f65d170..02acfafd6 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTaskConcurrentException.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTaskConcurrentException.cs @@ -1,17 +1,15 @@ using System; -using Volo.Abp; namespace LINGYUN.Abp.BackgroundTasks; -public class AbpBackgroundTaskConcurrentException : AbpException +public class AbpBackgroundTaskConcurrentException : AbpJobExecutionException { - public Type JobType { get; } /// /// Creates a new object. /// /// Inner exception public AbpBackgroundTaskConcurrentException(Type jobType) - : this( + : base( jobType, $"This job {jobType.Name} cannot be performed because it has been locked by another performer", null) @@ -24,7 +22,7 @@ public class AbpBackgroundTaskConcurrentException : AbpException /// Execute job type /// Inner exception public AbpBackgroundTaskConcurrentException(Type jobType, Exception innerException) - : this( + : base( jobType, $"This job {jobType.Name} cannot be performed because it has been locked by another performer", innerException) @@ -38,8 +36,7 @@ public class AbpBackgroundTaskConcurrentException : AbpException /// Exception message /// Inner exception public AbpBackgroundTaskConcurrentException(Type jobType, string message, Exception innerException) - : base(message, innerException) + : base(jobType, message, innerException) { - JobType = jobType; } } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksAbstractionsModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksAbstractionsModule.cs index 3e349c78c..5ad3b3a60 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksAbstractionsModule.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksAbstractionsModule.cs @@ -1,7 +1,33 @@ -using Volo.Abp.Modularity; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using Volo.Abp.Modularity; +using Volo.Abp.Reflection; namespace LINGYUN.Abp.BackgroundTasks; public class AbpBackgroundTasksAbstractionsModule : AbpModule { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + AutoAddJobMonitors(context.Services); + } + + private static void AutoAddJobMonitors(IServiceCollection services) + { + var jobMonitors = new List(); + + services.OnRegistred(context => + { + if (ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(JobEventBase<>))) + { + jobMonitors.Add(context.ImplementationType); + } + }); + + services.Configure(options => + { + options.JobMonitors.AddIfNotContains(jobMonitors); + }); + } } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs similarity index 78% rename from aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs rename to aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs index 69457817b..788102a83 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Volo.Abp.Collections; namespace LINGYUN.Abp.BackgroundTasks; @@ -13,6 +14,13 @@ public class AbpBackgroundTasksOptions /// public ITypeList JobMonitors { get; } /// + /// 作业提供者列表 + /// + /// + /// 用户实现的作业可以添加在集合中 + /// + public IDictionary JobProviders { get; } + /// /// 任务过期时间 /// 默认: 15 days /// @@ -65,5 +73,12 @@ public class AbpBackgroundTasksOptions JobCleanCronExpression = "0 0/10 * * * ? *"; JobMonitors = new TypeList(); + JobProviders = new Dictionary(); + } + + public void AddProvider(string name) + where TJobRunnable : IJobRunnable + { + JobProviders[name] = typeof(TJobRunnable); } } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpJobExecutionException.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpJobExecutionException.cs new file mode 100644 index 000000000..3de421a9b --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpJobExecutionException.cs @@ -0,0 +1,44 @@ +using System; +using Volo.Abp; + +namespace LINGYUN.Abp.BackgroundTasks; + +public class AbpJobExecutionException : AbpException +{ + public Type JobType { get; } + /// + /// Creates a new object. + /// + /// Inner exception + public AbpJobExecutionException(Type jobType) + : this( + jobType, + $"Unable to execute job {jobType.Name}.", + null) + { + } + + /// + /// Creates a new object. + /// + /// Execute job type + /// Inner exception + public AbpJobExecutionException(Type jobType, Exception innerException) + : this( + jobType, + $"Unable to execute job {jobType.Name} because it: {innerException.Message}", + innerException) + { + } + /// + /// Creates a new object. + /// + /// Execute job type + /// Exception message + /// Inner exception + public AbpJobExecutionException(Type jobType, string message, Exception innerException) + : base(message, innerException) + { + JobType = jobType; + } +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobEvent.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobEvent.cs similarity index 100% rename from aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobEvent.cs rename to aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobEvent.cs diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobEventBase.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobEventBase.cs similarity index 100% rename from aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobEventBase.cs rename to aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobEventBase.cs diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobRunnableContext.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobRunnableContext.cs index 75af712ad..96f366af8 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobRunnableContext.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobRunnableContext.cs @@ -8,6 +8,7 @@ public class JobRunnableContext public Type JobType { get; } public IServiceProvider ServiceProvider { get; } public IReadOnlyDictionary JobData { get; } + public object Result { get; private set; } public JobRunnableContext( Type jobType, IServiceProvider serviceProvider, @@ -17,4 +18,9 @@ public class JobRunnableContext ServiceProvider = serviceProvider; JobData = jobData; } + + public void SetResult(object result) + { + Result = result; + } } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobRunnableContextExtensions.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobRunnableContextExtensions.cs new file mode 100644 index 000000000..f2fe7510b --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobRunnableContextExtensions.cs @@ -0,0 +1,85 @@ +using Microsoft.Extensions.DependencyInjection; +using System; + +namespace LINGYUN.Abp.BackgroundTasks; + +public static class JobRunnableContextExtensions +{ + public static T GetService(this JobRunnableContext context) + { + return context.ServiceProvider.GetService(); + } + + public static object GetService(this JobRunnableContext context, Type serviceType) + { + return context.ServiceProvider.GetService(serviceType); + } + + public static T GetRequiredService(this JobRunnableContext context) + { + return context.ServiceProvider.GetRequiredService(); + } + + public static object GetRequiredService(this JobRunnableContext context, Type serviceType) + { + return context.ServiceProvider.GetRequiredService(serviceType); + } + + public static string GetString(this JobRunnableContext context, string key) + { + return context.GetJobData(key).ToString(); + } + + public static bool TryGetString(this JobRunnableContext context, string key, out string value) + { + if (context.TryGetJobData(key, out var data) && data != null) + { + value = data.ToString(); + return true; + } + value = default; + return false; + } + + public static T GetJobData(this JobRunnableContext context, string key) where T : struct + { + var value = context.GetJobData(key); + + return value.To(); + } + + public static bool TryGetJobData(this JobRunnableContext context, string key, out T value) where T : struct + { + if (context.TryGetJobData(key, out var data) && data != null) + { + try + { + value = data.To(); + return true; + } + catch + { + } + } + value = default; + return false; + } + + public static object GetJobData(this JobRunnableContext context, string key) + { + if (context.TryGetJobData(key, out var value) && value != null) + { + return value; + } + throw new ArgumentException(key + " not specified."); + } + + public static bool TryGetJobData(this JobRunnableContext context, string key, out object value) + { + if (context.JobData.TryGetValue(key, out value)) + { + return true; + } + return false; + } +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/FodyWeavers.xml b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/FodyWeavers.xml new file mode 100644 index 000000000..ac6b5b292 --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/FodyWeavers.xsd b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN.Abp.BackgroundTasks.Jobs.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN.Abp.BackgroundTasks.Jobs.csproj new file mode 100644 index 000000000..f7afc48e8 --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN.Abp.BackgroundTasks.Jobs.csproj @@ -0,0 +1,21 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/AbpBackgroundTasksJobsModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/AbpBackgroundTasksJobsModule.cs new file mode 100644 index 000000000..b0ccd972a --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/AbpBackgroundTasksJobsModule.cs @@ -0,0 +1,25 @@ +using Volo.Abp.Emailing; +using Volo.Abp.Http.Client; +using Volo.Abp.Modularity; +using Volo.Abp.Sms; + +namespace LINGYUN.Abp.BackgroundTasks.Jobs; + +[DependsOn(typeof(AbpEmailingModule))] +[DependsOn(typeof(AbpSmsModule))] +[DependsOn(typeof(AbpHttpClientModule))] +public class AbpBackgroundTasksJobsModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.AddProvider(DefaultJobNames.ConsoleJob); + options.AddProvider(DefaultJobNames.SendEmailJob); + options.AddProvider(DefaultJobNames.SendSmsJob); + options.AddProvider(DefaultJobNames.SleepJob); + options.AddProvider(DefaultJobNames.ServiceInvocationJob); + options.AddProvider(DefaultJobNames.HttpRequestJob); + }); + } +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/ConsoleJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/ConsoleJob.cs similarity index 81% rename from aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/ConsoleJob.cs rename to aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/ConsoleJob.cs index a108d492c..52377cb0e 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/ConsoleJob.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/ConsoleJob.cs @@ -1,7 +1,7 @@ using System; using System.Threading.Tasks; -namespace LINGYUN.Abp.BackgroundTasks.Primitives; +namespace LINGYUN.Abp.BackgroundTasks.Jobs; public class ConsoleJob : IJobRunnable { diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/DefaultJobNames.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/DefaultJobNames.cs new file mode 100644 index 000000000..b8527766d --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/DefaultJobNames.cs @@ -0,0 +1,29 @@ +namespace LINGYUN.Abp.BackgroundTasks.Jobs; + +public static class DefaultJobNames +{ + /// + /// 发送邮件 + /// + public const string SendEmailJob = "SendEmail"; + /// + /// 发送短信 + /// + public const string SendSmsJob = "SendSms"; + /// + /// 控制台输出 + /// + public const string ConsoleJob = "Console"; + /// + /// 休眠 + /// + public const string SleepJob = "Sleep"; + /// + /// 服务间调用 + /// + public const string ServiceInvocationJob = "ServiceInvocation"; + /// + /// Http请求 + /// + public const string HttpRequestJob = "HttpRequest"; +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/HttpRequestJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/HttpRequestJob.cs new file mode 100644 index 000000000..c3849914a --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/HttpRequestJob.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Http; +using Volo.Abp.Json; + +namespace LINGYUN.Abp.BackgroundTasks.Jobs; + +public class HttpRequestJob : IJobRunnable +{ + public const string PropertyUrl = "url"; + public const string PropertyMethod = "method"; + public const string PropertyData = "data"; + public const string PropertyContentType = "contentType"; + public const string PropertyHeaders = "headers"; + public const string PropertyToken = "token"; + + public virtual async Task ExecuteAsync(JobRunnableContext context) + { + var clientFactory = context.GetRequiredService(); + + var client = clientFactory.CreateClient(); + var requestMessage = BuildRequestMessage(context); + + var response = await client.SendAsync( + requestMessage, + HttpCompletionOption.ResponseHeadersRead); + + var stringContent = await response.Content.ReadAsStringAsync(); + + if (!response.IsSuccessStatusCode && stringContent.IsNullOrWhiteSpace()) + { + context.SetResult($"HttpStatusCode: {(int)response.StatusCode}, Reason: {response.ReasonPhrase}"); + return; + } + context.SetResult(stringContent); + } + + protected virtual HttpRequestMessage BuildRequestMessage(JobRunnableContext context) + { + var url = context.GetString(PropertyUrl); + var method = context.GetString(PropertyMethod); + context.TryGetJobData(PropertyData, out var data); + context.TryGetJobData(PropertyContentType, out var contentType); + + var jsonSerializer = context.GetRequiredService(); + + var httpRequestMesasge = new HttpRequestMessage(new HttpMethod(method), url); + if (data != null) + { + // TODO: 需要支持表单类型 + + // application/json 支持 + httpRequestMesasge.Content = new StringContent( + jsonSerializer.Serialize(data), + Encoding.UTF8, + contentType?.ToString() ?? MimeTypes.Application.Json); + } + if (context.TryGetJobData(PropertyHeaders, out var headers) && + headers is IDictionary headersDic) + { + foreach (var header in headersDic) + { + httpRequestMesasge.Headers.Add(header.Key, header.Value); + } + } + // TODO: 和 headers 一起? + if (context.TryGetString(PropertyToken, out var accessToken)) + { + httpRequestMesasge.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); + } + + return httpRequestMesasge; + } +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/SendEmailJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/SendEmailJob.cs new file mode 100644 index 000000000..765c35db6 --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/SendEmailJob.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using Volo.Abp.Emailing; + +namespace LINGYUN.Abp.BackgroundTasks.Jobs; + +public class SendEmailJob : IJobRunnable +{ + public const string PropertyFrom = "from"; + public const string PropertyTo = "to"; + public const string PropertySubject = "subject"; + public const string PropertyBody = "body"; + public const string PropertyIsBodyHtml = "isBodyHtml"; + + public virtual async Task ExecuteAsync(JobRunnableContext context) + { + context.TryGetString(PropertyFrom, out var from); + var to = context.GetString(PropertyTo); + var subject = context.GetString(PropertySubject); + var body = context.GetString(PropertyBody); + context.TryGetJobData(PropertyIsBodyHtml, out var isBodyHtml); + + var emailSender = context.GetRequiredService(); + + await emailSender.QueueAsync(from, to, subject, body, isBodyHtml); + } +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/SendSmsJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/SendSmsJob.cs new file mode 100644 index 000000000..7d3cc2463 --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/SendSmsJob.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Sms; + +namespace LINGYUN.Abp.BackgroundTasks.Jobs; + +public class SendSmsJob : IJobRunnable +{ + public const string PropertyPhoneNumber = "phoneNumber"; + public const string PropertyMessage = "message"; + public const string PropertyProperties = "properties"; + + public virtual async Task ExecuteAsync(JobRunnableContext context) + { + var phoneNumber = context.GetString(PropertyPhoneNumber); + var message = context.GetString(PropertyMessage); + + var smsMessage = new SmsMessage(phoneNumber, message); + if (context.TryGetJobData(PropertyProperties, out var data) && + data is IDictionary properties) + { + smsMessage.Properties.AddIfNotContains(properties); + } + + var smsSender = context.GetRequiredService(); + + await smsSender.SendAsync(smsMessage); + } +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/ServiceInvocationJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/ServiceInvocationJob.cs new file mode 100644 index 000000000..19ba601c4 --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/ServiceInvocationJob.cs @@ -0,0 +1,117 @@ +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Http.Client; +using Volo.Abp.Http.Client.ClientProxying; +using Volo.Abp.Http.Client.DynamicProxying; +using Volo.Abp.Http.Client.Proxying; +using Volo.Abp.Http.Modeling; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.BackgroundTasks.Jobs; + +public class ServiceInvocationJob : IJobRunnable +{ + public const string PropertyService = "service"; + public const string PropertyMethod = "method"; + public const string PropertyCulture = "culture"; + + public virtual async Task ExecuteAsync(JobRunnableContext context) + { + // 获取参数列表 + var type = context.GetString(PropertyService); + var method = context.GetString(PropertyMethod); + var serviceType = Type.GetType(type, true); + var serviceMethod = serviceType.GetMethod(method); + context.TryGetString(PropertyCulture, out var culture); + + using (CultureHelper.Use(culture ?? CultureInfo.CurrentCulture.Name)) + { + // 反射所必须的参数 + var callRequestMethod = nameof(DynamicHttpProxyInterceptorClientProxy.CallRequestAsync); + var clientProxyType = typeof(DynamicHttpProxyInterceptorClientProxy<>).MakeGenericType(serviceType); + var clientProxy = context.GetRequiredService(clientProxyType); + var clientProxyMethod = typeof(DynamicHttpProxyInterceptorClientProxy<>).GetMethod(callRequestMethod); + + // 调用远程服务发现端点 + var actionApiDescription = await GetActionApiDescriptionModel(context, serviceType, serviceMethod); + + // 拼接调用参数 + var invokeParameters = new Dictionary(); + var methodParameters = serviceMethod.GetParameters(); + foreach (var parameter in methodParameters) + { + if (context.TryGetJobData(parameter.Name, out var value)) + { + invokeParameters.Add(parameter.Name, value); + } + } + + // 构造服务代理上下文 + var clientProxyRequestContext = new ClientProxyRequestContext( + actionApiDescription, + invokeParameters, + serviceType); + + if (serviceMethod.ReturnType.GenericTypeArguments.IsNullOrEmpty()) + { + // 直接调用 + var taskProxy = (Task)clientProxyMethod.Invoke(clientProxy, new object[] { clientProxyRequestContext }); + await taskProxy; + } + else + { + // 有返回值的调用 + + var callRequestAsyncMethod = typeof(DynamicHttpProxyInterceptor) + .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) + .First(m => m.Name == callRequestMethod && m.IsGenericMethodDefinition); + + var returnType = serviceMethod.ReturnType.GenericTypeArguments[0]; + var result = (Task)callRequestAsyncMethod + .MakeGenericMethod(returnType) + .Invoke(this, new object[] { context }); + + context.SetResult(await GetResultAsync(result, returnType)); + } + } + } + + protected virtual async Task GetActionApiDescriptionModel( + JobRunnableContext context, + Type serviceType, + MethodInfo method) + { + var clientOptions = context.GetRequiredService>().Value; + var remoteServiceConfigurationProvider = context.GetRequiredService(); + var proxyHttpClientFactory = context.GetRequiredService(); + var apiDescriptionFinder = context.GetRequiredService(); + + var clientConfig = clientOptions.HttpClientProxies.GetOrDefault(serviceType) ?? + throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {serviceType.FullName}."); + var remoteServiceConfig = await remoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync(clientConfig.RemoteServiceName); + var client = proxyHttpClientFactory.Create(clientConfig.RemoteServiceName); + + return await apiDescriptionFinder.FindActionAsync( + client, + remoteServiceConfig.BaseUrl, + serviceType, + method + ); + } + + protected virtual async Task GetResultAsync(Task task, Type resultType) + { + await task; + var resultProperty = typeof(Task<>) + .MakeGenericType(resultType) + .GetProperty(nameof(Task.Result), BindingFlags.Instance | BindingFlags.Public); + Check.NotNull(resultProperty, nameof(resultProperty)); + return resultProperty.GetValue(task); + } +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/SleepJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/SleepJob.cs similarity index 84% rename from aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/SleepJob.cs rename to aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/SleepJob.cs index d2f65f17e..9ec6be494 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/SleepJob.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/SleepJob.cs @@ -1,7 +1,7 @@ using System; using System.Threading.Tasks; -namespace LINGYUN.Abp.BackgroundTasks.Primitives; +namespace LINGYUN.Abp.BackgroundTasks.Jobs; public class SleepJob : IJobRunnable { diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobExecutorProvider.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobExecutorProvider.cs index 45f35155e..2c14fa422 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobExecutorProvider.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobExecutorProvider.cs @@ -3,6 +3,7 @@ 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; @@ -27,7 +28,7 @@ public class QuartzJobExecutorProvider : IQuartzJobExecutorProvider, ISingletonD public IJobDetail CreateJob(JobInfo job) { - var jobType = Type.GetType(job.Type); + var jobType = Type.GetType(job.Type) ?? Options.JobProviders.GetOrDefault(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."); diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobSimpleAdapter.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobSimpleAdapter.cs index 55b65a3af..7f411b16f 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobSimpleAdapter.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobSimpleAdapter.cs @@ -29,5 +29,7 @@ public class QuartzJobSimpleAdapter : IJob context.MergedJobDataMap.ToImmutableDictionary()); await jobExecuter.ExecuteAsync(jobContext); + + context.Result = jobContext.Result; } } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksModule.cs index 2ee46ed95..94c50a110 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksModule.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksModule.cs @@ -1,13 +1,10 @@ using LINGYUN.Abp.BackgroundTasks.Internal; using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; using Volo.Abp.Auditing; using Volo.Abp.BackgroundJobs; using Volo.Abp.DistributedLocking; using Volo.Abp.Guids; using Volo.Abp.Modularity; -using Volo.Abp.Reflection; namespace LINGYUN.Abp.BackgroundTasks; @@ -18,32 +15,9 @@ namespace LINGYUN.Abp.BackgroundTasks; [DependsOn(typeof(AbpGuidsModule))] public class AbpBackgroundTasksModule : AbpModule { - public override void PreConfigureServices(ServiceConfigurationContext context) - { - AutoAddJobMonitors(context.Services); - } - public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddTransient(typeof(BackgroundJobAdapter<>)); context.Services.AddHostedService(); } - - private static void AutoAddJobMonitors(IServiceCollection services) - { - var jobMonitors = new List(); - - services.OnRegistred(context => - { - if (ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(JobEventBase<>))) - { - jobMonitors.Add(context.ImplementationType); - } - }); - - services.Configure(options => - { - options.JobMonitors.AddIfNotContains(jobMonitors); - }); - } } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/EmailingJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/EmailingJob.cs deleted file mode 100644 index b8e3f95e8..000000000 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/EmailingJob.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace LINGYUN.Abp.BackgroundTasks.Primitives; - -public class EmailingJob : IJobRunnable -{ - public virtual async Task ExecuteAsync(JobRunnableContext context) - { - - } -} diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/LY.MicroService.TaskManagement.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/LY.MicroService.TaskManagement.HttpApi.Host.csproj index ccec8e8b2..1610fecc9 100644 --- a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/LY.MicroService.TaskManagement.HttpApi.Host.csproj +++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/LY.MicroService.TaskManagement.HttpApi.Host.csproj @@ -50,6 +50,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs index ef8042545..1626a8402 100644 --- a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs @@ -1,4 +1,5 @@ using LINGYUN.Abp.AuditLogging.Elasticsearch; +using LINGYUN.Abp.BackgroundTasks.Jobs; using LINGYUN.Abp.BackgroundTasks.Quartz; using LINGYUN.Abp.Data.DbMigrator; using LINGYUN.Abp.ExceptionHandling.Emailing; @@ -42,6 +43,7 @@ namespace LY.MicroService.TaskManagement; typeof(AbpHttpClientIdentityModelWebModule), typeof(AbpAspNetCoreMultiTenancyModule), typeof(AbpDbFinderMultiTenancyModule), + typeof(AbpBackgroundTasksJobsModule), typeof(AbpBackgroundTasksQuartzModule), typeof(TaskManagementApplicationModule), typeof(TaskManagementHttpApiModule),