From 1aa76432419abc60bc7b7d5b026db741fe5bc4f0 Mon Sep 17 00:00:00 2001 From: colin Date: Sun, 25 Jun 2023 09:27:03 +0800 Subject: [PATCH] feat(jobs): add elasticsearch jobs. --- .../LINGYUN.MicroService.TaskManagement.sln | 18 ++- .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++++ .../LINGYUN.Abp.Elasticsearch.Jobs.csproj | 28 +++++ .../Jobs/AbpElasticsearchJobsModule.cs | 29 +++++ .../ElasticsearchJobDefinitionProvider.cs | 16 +++ .../Jobs/ExpiredIndicesCleanupJob.cs | 114 ++++++++++++++++++ .../Elasticsearch/Jobs/LocalizableStatic.cs | 12 ++ .../Localization/ElasticsearchJobsResource.cs | 8 ++ .../Jobs/Localization/Resources/en.json | 10 ++ .../Jobs/Localization/Resources/zh-Hans.json | 10 ++ .../JobRunnableContextExtensions.cs | 20 +++ 12 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/FodyWeavers.xml create mode 100644 aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/FodyWeavers.xsd create mode 100644 aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN.Abp.Elasticsearch.Jobs.csproj create mode 100644 aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/AbpElasticsearchJobsModule.cs create mode 100644 aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/ElasticsearchJobDefinitionProvider.cs create mode 100644 aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/ExpiredIndicesCleanupJob.cs create mode 100644 aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/LocalizableStatic.cs create mode 100644 aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/Localization/ElasticsearchJobsResource.cs create mode 100644 aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/Localization/Resources/en.json create mode 100644 aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/Localization/Resources/zh-Hans.json diff --git a/aspnet-core/LINGYUN.MicroService.TaskManagement.sln b/aspnet-core/LINGYUN.MicroService.TaskManagement.sln index 04fc3f6c9..819bd6a40 100644 --- a/aspnet-core/LINGYUN.MicroService.TaskManagement.sln +++ b/aspnet-core/LINGYUN.MicroService.TaskManagement.sln @@ -84,7 +84,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "migrations", "migrations", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LY.MicroService.TaskManagement.DbMigrator", "migrations\LY.MicroService.TaskManagement.DbMigrator\LY.MicroService.TaskManagement.DbMigrator.csproj", "{52FD8F39-0AB6-4C51-A584-187C219AC8B5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LY.MicroService.TaskManagement.EntityFrameworkCore", "migrations\LY.MicroService.TaskManagement.EntityFrameworkCore\LY.MicroService.TaskManagement.EntityFrameworkCore.csproj", "{58F51875-6D2C-4A65-9DD3-8BC004B39B72}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LY.MicroService.TaskManagement.EntityFrameworkCore", "migrations\LY.MicroService.TaskManagement.EntityFrameworkCore\LY.MicroService.TaskManagement.EntityFrameworkCore.csproj", "{58F51875-6D2C-4A65-9DD3-8BC004B39B72}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "elasticsearch", "elasticsearch", "{DC7ACD8B-044B-435D-94C5-06C75A8BD026}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Elasticsearch", "modules\elasticsearch\LINGYUN.Abp.Elasticsearch\LINGYUN.Abp.Elasticsearch.csproj", "{167CE485-72D3-4E95-80B1-00430CBB8888}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Elasticsearch.Jobs", "modules\elasticsearch\LINGYUN.Abp.Elasticsearch.Jobs\LINGYUN.Abp.Elasticsearch.Jobs.csproj", "{798FEFB4-B65F-4B6C-A36D-611DD71A48AB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -212,6 +218,14 @@ Global {58F51875-6D2C-4A65-9DD3-8BC004B39B72}.Debug|Any CPU.Build.0 = Debug|Any CPU {58F51875-6D2C-4A65-9DD3-8BC004B39B72}.Release|Any CPU.ActiveCfg = Release|Any CPU {58F51875-6D2C-4A65-9DD3-8BC004B39B72}.Release|Any CPU.Build.0 = Release|Any CPU + {167CE485-72D3-4E95-80B1-00430CBB8888}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {167CE485-72D3-4E95-80B1-00430CBB8888}.Debug|Any CPU.Build.0 = Debug|Any CPU + {167CE485-72D3-4E95-80B1-00430CBB8888}.Release|Any CPU.ActiveCfg = Release|Any CPU + {167CE485-72D3-4E95-80B1-00430CBB8888}.Release|Any CPU.Build.0 = Release|Any CPU + {798FEFB4-B65F-4B6C-A36D-611DD71A48AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {798FEFB4-B65F-4B6C-A36D-611DD71A48AB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {798FEFB4-B65F-4B6C-A36D-611DD71A48AB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {798FEFB4-B65F-4B6C-A36D-611DD71A48AB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -247,6 +261,8 @@ Global {DF963ABB-E713-49E9-A03C-DEB431E369DF} = {B38D2141-AC0F-4F4A-9315-4292E3856C15} {52FD8F39-0AB6-4C51-A584-187C219AC8B5} = {820A8FA4-17C4-44DF-8C31-9F211D00F790} {58F51875-6D2C-4A65-9DD3-8BC004B39B72} = {820A8FA4-17C4-44DF-8C31-9F211D00F790} + {167CE485-72D3-4E95-80B1-00430CBB8888} = {DC7ACD8B-044B-435D-94C5-06C75A8BD026} + {798FEFB4-B65F-4B6C-A36D-611DD71A48AB} = {A9536BD2-2573-44CA-B033-DC16B7E345E5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E1FD1F4C-D344-408B-97CF-B6F1F6D7D293} diff --git a/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/FodyWeavers.xml b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/FodyWeavers.xsd b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.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/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN.Abp.Elasticsearch.Jobs.csproj b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN.Abp.Elasticsearch.Jobs.csproj new file mode 100644 index 000000000..dee000c39 --- /dev/null +++ b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN.Abp.Elasticsearch.Jobs.csproj @@ -0,0 +1,28 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/AbpElasticsearchJobsModule.cs b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/AbpElasticsearchJobsModule.cs new file mode 100644 index 000000000..bb0949a9b --- /dev/null +++ b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/AbpElasticsearchJobsModule.cs @@ -0,0 +1,29 @@ +using LINGYUN.Abp.BackgroundTasks; +using LINGYUN.Abp.Elasticsearch.Jobs.Localization; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.Timing; +using Volo.Abp.VirtualFileSystem; + +namespace LINGYUN.Abp.Elasticsearch.Jobs; + +[DependsOn(typeof(AbpTimingModule))] +[DependsOn(typeof(AbpElasticsearchModule))] +[DependsOn(typeof(AbpBackgroundTasksAbstractionsModule))] +public class AbpElasticsearchJobsModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Add() + .AddVirtualJson("/LINGYUN/Abp/Elasticsearch/Jobs/Localization/Resources"); + }); + } +} \ No newline at end of file diff --git a/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/ElasticsearchJobDefinitionProvider.cs b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/ElasticsearchJobDefinitionProvider.cs new file mode 100644 index 000000000..d9d2a4a83 --- /dev/null +++ b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/ElasticsearchJobDefinitionProvider.cs @@ -0,0 +1,16 @@ +using LINGYUN.Abp.BackgroundTasks; + +namespace LINGYUN.Abp.Elasticsearch.Jobs; + +public class NotificationJobDefinitionProvider : JobDefinitionProvider +{ + public override void Define(IJobDefinitionContext context) + { + context.Add( + new JobDefinition( + ExpiredIndicesCleanupJob.Name, + typeof(ExpiredIndicesCleanupJob), + LocalizableStatic.Create("IndicesCleanupJob"), + ExpiredIndicesCleanupJob.Paramters)); + } +} diff --git a/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/ExpiredIndicesCleanupJob.cs b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/ExpiredIndicesCleanupJob.cs new file mode 100644 index 000000000..8817d765f --- /dev/null +++ b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/ExpiredIndicesCleanupJob.cs @@ -0,0 +1,114 @@ +using LINGYUN.Abp.BackgroundTasks; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Timing; + +namespace LINGYUN.Abp.Elasticsearch.Jobs; + +/// +/// Elasticsearch 过期索引清理作业 +/// +public class ExpiredIndicesCleanupJob : IJobRunnable +{ + #region Definition Paramters + + public readonly static IReadOnlyList Paramters = + new List + { + new JobDefinitionParamter( + PropertyIndexPrefix, + LocalizableStatic.Create("Indices:IndexPrefix"), + required: true), + new JobDefinitionParamter( + PropertyTimeZone, + LocalizableStatic.Create("Indices:TimeZone"), + LocalizableStatic.Create("Indices:TimeZoneDesc")), + new JobDefinitionParamter( + PropertyExpirationTime, + LocalizableStatic.Create("Indices:ExpirationTime")), + }; + + public const string Name = "ExpiredIndicesCleanupJob"; + /// + /// 每次清除记录大小 + /// + private const string PropertyIndexPrefix = "IndexPrefix"; + /// + /// 计算时差的时区, 默认Utc + /// + private const string PropertyTimeZone = "TimeZone"; + /// + /// 过期时间, 单位秒, 默认 5184000 (60天) + /// + private const string PropertyExpirationTime = "ExpirationTime"; + + #endregion + + public async virtual Task ExecuteAsync(JobRunnableContext context) + { + #region Initializes Job Parameters + + var timeZone = TimeZoneInfo.Utc; + var indexPrefix = context.GetString(PropertyIndexPrefix); + var timeZoneString = context.GetOrDefaultString(PropertyTimeZone, "utc"); + var expirationSecond = context.GetOrDefaultJobData(PropertyExpirationTime, 5184000L); + + if (!timeZoneString.IsNullOrWhiteSpace()) + { + timeZone = timeZoneString.ToLowerInvariant() switch + { + "local" => TimeZoneInfo.Local, + _ => TimeZoneInfo.Utc, + }; + } + + var elasticClientFactory = context.GetRequiredService(); + var elasticClient = elasticClientFactory.Create(); + + var clock = context.GetRequiredService(); + var expirationTime = clock.Now.AddSeconds(-expirationSecond); + var startTime = TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), timeZone); + var removeIndices = new List(); + + #endregion + + #region ES indices.get_settings API + + // GET demo*/_settings + var settingResponse = await elasticClient.Indices.GetSettingsAsync(indexPrefix); + if (!settingResponse.IsValid) + { + throw new AbpJobExecutionException(GetType(), settingResponse.ServerError.ToString(), settingResponse.OriginalException); + } + + foreach (var indexSet in settingResponse.Indices) + { + // 索引创建日期 + if (indexSet.Value.Settings.TryGetValue("index.creation_date", out var indexSetV) && + long.TryParse(indexSetV.ToString(), out var timestamp)) + { + var indexCreationDate = startTime.AddMilliseconds(timestamp); + if (indexCreationDate <= expirationTime) + { + removeIndices.Add(indexSet.Key.Name); + } + } + } + + #endregion + + #region ES indices.delete API + + foreach (var index in removeIndices) + { + var delResponse = await elasticClient.Indices.DeleteAsync(index); + if (!delResponse.IsValid) + { + throw new AbpJobExecutionException(GetType(), delResponse.ServerError.ToString(), delResponse.OriginalException); + } + } + + #endregion + } +} diff --git a/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/LocalizableStatic.cs b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/LocalizableStatic.cs new file mode 100644 index 000000000..4c1d3fcf5 --- /dev/null +++ b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/LocalizableStatic.cs @@ -0,0 +1,12 @@ +using LINGYUN.Abp.Elasticsearch.Jobs.Localization; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.Elasticsearch.Jobs; + +internal static class LocalizableStatic +{ + public static ILocalizableString Create(string name) + { + return LocalizableString.Create(name); + } +} diff --git a/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/Localization/ElasticsearchJobsResource.cs b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/Localization/ElasticsearchJobsResource.cs new file mode 100644 index 000000000..d8752f225 --- /dev/null +++ b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/Localization/ElasticsearchJobsResource.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.Elasticsearch.Jobs.Localization; + +[LocalizationResourceName("ElasticsearchJobs")] +public class ElasticsearchJobsResource +{ +} diff --git a/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/Localization/Resources/en.json b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/Localization/Resources/en.json new file mode 100644 index 000000000..605aeb326 --- /dev/null +++ b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/Localization/Resources/en.json @@ -0,0 +1,10 @@ +{ + "culture": "en", + "texts": { + "IndicesCleanupJob": "Expired index cleanup job", + "Indices:IndexPrefix": "Index prefix", + "Indices:TimeZone": "Timezone", + "Indices:TimeZoneDesc": "Time zone for calculating the time difference, default Utc, optional (Utc, Local).", + "Indices:ExpirationTime": "Expiration time(seconds)" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/Localization/Resources/zh-Hans.json b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/Localization/Resources/zh-Hans.json new file mode 100644 index 000000000..ecf73db34 --- /dev/null +++ b/aspnet-core/modules/elasticsearch/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN/Abp/Elasticsearch/Jobs/Localization/Resources/zh-Hans.json @@ -0,0 +1,10 @@ +{ + "culture": "zh-Hans", + "texts": { + "IndicesCleanupJob": "过期索引清理作业", + "Indices:IndexPrefix": "索引前缀", + "Indices:TimeZone": "时区", + "Indices:TimeZoneDesc": "计算时差的时区, 默认Utc, 可选(Utc、Local)", + "Indices:ExpirationTime": "过期时间(秒)" + } +} \ No newline at end of file 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 index a9ac515da..f5da58d43 100644 --- 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 @@ -30,6 +30,16 @@ public static class JobRunnableContextExtensions return context.GetJobData(key).ToString(); } + public static string GetOrDefaultString(this JobRunnableContext context, string key, string defaultValue = "") + { + if (context.TryGetString(key, out var value)) + { + return value; + } + + return defaultValue; + } + public static bool TryGetString(this JobRunnableContext context, string key, out string value) { if (context.TryGetJobData(key, out var data) && data != null) @@ -65,6 +75,16 @@ public static class JobRunnableContextExtensions return value.To(); } + public static T GetOrDefaultJobData(this JobRunnableContext context, string key, T defaultValue) where T : struct + { + if (context.TryGetJobData(key, out var value)) + { + return value; + } + + return defaultValue; + } + public static bool TryGetJobData(this JobRunnableContext context, string key, out T value) where T : struct { if (context.TryGetJobData(key, out var data) && data != null)