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 bb0139e9d..1923355db 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 @@ -41,6 +41,18 @@ public static class JobRunnableContextExtensions return false; } + public static bool TryGetMultiTenantId(this JobRunnableContext context, out Guid? tenantId) + { + tenantId = null; + if (context.TryGetString(nameof(JobInfo.TenantId), out var tenantUUIdString) && + Guid.TryParse(tenantUUIdString, out var tenantUUId)) + { + tenantId = tenantUUId; + return true; + } + return false; + } + public static T GetJobData(this JobRunnableContext context, string key) where T : struct { var value = context.GetJobData(key); diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/AbpBackgroundTasksQuartzModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/AbpBackgroundTasksQuartzModule.cs index 788825614..da7045354 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/AbpBackgroundTasksQuartzModule.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/AbpBackgroundTasksQuartzModule.cs @@ -1,5 +1,7 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using Quartz; +using System.Collections.Specialized; using Volo.Abp; using Volo.Abp.Modularity; using Volo.Abp.Quartz; diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/IQuartzKeyBuilder.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/IQuartzKeyBuilder.cs new file mode 100644 index 000000000..7a8f082fd --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/IQuartzKeyBuilder.cs @@ -0,0 +1,10 @@ +using Quartz; + +namespace LINGYUN.Abp.BackgroundTasks.Quartz; + +public interface IQuartzKeyBuilder +{ + JobKey CreateJobKey(JobInfo jobInfo); + + TriggerKey CreateTriggerKey(JobInfo jobInfo); +} 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 23b67f1c8..2b2b6e388 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 @@ -15,20 +15,22 @@ public class QuartzJobExecutorProvider : IQuartzJobExecutorProvider, ISingletonD protected IClock Clock { get; } protected AbpBackgroundTasksOptions Options { get; } - + protected IQuartzKeyBuilder KeyBuilder { get; } public QuartzJobExecutorProvider( IClock clock, + IQuartzKeyBuilder keyBuilder, IOptions options) { Clock = clock; Options = options.Value; + KeyBuilder = keyBuilder; Logger = NullLogger.Instance; } public IJobDetail CreateJob(JobInfo job) { - var jobType = Type.GetType(job.Type) ?? Options.JobProviders.GetOrDefault(job.Type); + var jobType = Options.JobProviders.GetOrDefault(job.Type) ?? 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."); @@ -50,7 +52,7 @@ public class QuartzJobExecutorProvider : IQuartzJobExecutorProvider, ISingletonD // 改为 JobId作为名称 var jobBuilder = JobBuilder.Create(jobType) - .WithIdentity(job.Id.ToString(), job.Group) + .WithIdentity(KeyBuilder.CreateJobKey(job)) .WithDescription(job.Description); jobBuilder.UsingJobData(nameof(JobInfo.Id), job.Id); @@ -82,10 +84,10 @@ public class QuartzJobExecutorProvider : IQuartzJobExecutorProvider, ISingletonD return null; } triggerBuilder - .WithIdentity(job.Id.ToString(), job.Group) + .WithIdentity(KeyBuilder.CreateTriggerKey(job)) .WithDescription(job.Description) .EndAt(job.EndTime) - .ForJob(job.Id.ToString(), job.Group) + .ForJob(KeyBuilder.CreateJobKey(job)) .WithPriority((int)job.Priority) .WithCronSchedule(job.Cron); if (job.BeginTime > Clock.Now) @@ -111,11 +113,11 @@ public class QuartzJobExecutorProvider : IQuartzJobExecutorProvider, ISingletonD } triggerBuilder - .WithIdentity(job.Id.ToString(), job.Group) + .WithIdentity(KeyBuilder.CreateTriggerKey(job)) .WithDescription(job.Description) .StartAt(Clock.Now.AddSeconds(job.Interval)) .EndAt(job.EndTime) - .ForJob(job.Id.ToString(), job.Group) + .ForJob(KeyBuilder.CreateJobKey(job)) .WithPriority((int)job.Priority) .WithSimpleSchedule(x => x.WithIntervalInSeconds(job.Interval) diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobScheduler.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobScheduler.cs index baa9263c2..3113e94ef 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobScheduler.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobScheduler.cs @@ -10,27 +10,29 @@ public class QuartzJobScheduler : IJobScheduler, ISingletonDependency { protected IJobStore JobStore { get; } protected IScheduler Scheduler { get; } + protected IQuartzKeyBuilder KeyBuilder { get; } protected IQuartzJobExecutorProvider QuartzJobExecutor { get; } public QuartzJobScheduler( IJobStore jobStore, IScheduler scheduler, + IQuartzKeyBuilder keyBuilder, IQuartzJobExecutorProvider quartzJobExecutor) { JobStore = jobStore; Scheduler = scheduler; + KeyBuilder = keyBuilder; QuartzJobExecutor = quartzJobExecutor; } public virtual async Task ExistsAsync(JobInfo job) { - var jobKey = new JobKey(job.Id.ToString(), job.Group); - return await Scheduler.CheckExists(jobKey); + return await Scheduler.CheckExists(BuildJobKey(job)); } public virtual async Task PauseAsync(JobInfo job) { - var jobKey = new JobKey(job.Id.ToString(), job.Group); + var jobKey = BuildJobKey(job); if (await Scheduler.CheckExists(jobKey)) { var triggers = await Scheduler.GetTriggersOfJob(jobKey); @@ -43,7 +45,7 @@ public class QuartzJobScheduler : IJobScheduler, ISingletonDependency public virtual async Task QueueAsync(JobInfo job) { - var jobKey = new JobKey(job.Id.ToString(), job.Group); + var jobKey = BuildJobKey(job); if (await Scheduler.CheckExists(jobKey)) { return false; @@ -91,7 +93,7 @@ public class QuartzJobScheduler : IJobScheduler, ISingletonDependency public virtual async Task RemoveAsync(JobInfo job) { - var jobKey = new JobKey(job.Id.ToString(), job.Group); + var jobKey = BuildJobKey(job); if (!await Scheduler.CheckExists(jobKey)) { return false; @@ -109,7 +111,7 @@ public class QuartzJobScheduler : IJobScheduler, ISingletonDependency public virtual async Task ResumeAsync(JobInfo job) { - var jobKey = new JobKey(job.Id.ToString(), job.Group); + var jobKey = BuildJobKey(job); if (await Scheduler.CheckExists(jobKey)) { var triggers = await Scheduler.GetTriggersOfJob(jobKey); @@ -150,7 +152,7 @@ public class QuartzJobScheduler : IJobScheduler, ISingletonDependency public virtual async Task TriggerAsync(JobInfo job) { - var jobKey = new JobKey(job.Id.ToString(), job.Group); + var jobKey = BuildJobKey(job); if (!await Scheduler.CheckExists(jobKey)) { await QueueAsync(job); @@ -160,4 +162,9 @@ public class QuartzJobScheduler : IJobScheduler, ISingletonDependency await Scheduler.TriggerJob(jobKey); } } + + private JobKey BuildJobKey(JobInfo job) + { + return KeyBuilder.CreateJobKey(job); + } } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzKeyBuilder.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzKeyBuilder.cs new file mode 100644 index 000000000..57d685f2e --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzKeyBuilder.cs @@ -0,0 +1,35 @@ +using Quartz; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.BackgroundTasks.Quartz; + +public class QuartzKeyBuilder : IQuartzKeyBuilder, ISingletonDependency +{ + protected ICurrentTenant CurrentTenant { get; } + + public QuartzKeyBuilder(ICurrentTenant currentTenant) + { + CurrentTenant = currentTenant; + } + + public JobKey CreateJobKey(JobInfo jobInfo) + { + var name = jobInfo.Id.ToString(); + var group = CurrentTenant.IsAvailable + ? $"{CurrentTenant.Id}:{jobInfo.Group}" + : $"Default:{jobInfo.Group}"; + + return new JobKey(name, group); + } + + public TriggerKey CreateTriggerKey(JobInfo jobInfo) + { + var name = jobInfo.Id.ToString(); + var group = CurrentTenant.IsAvailable + ? $"{CurrentTenant.Id}:{jobInfo.Group}" + : $"Default:{jobInfo.Group}"; + + return new TriggerKey(name, group); + } +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundCleaningJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundCleaningJob.cs index f21537b5d..3544f3474 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundCleaningJob.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundCleaningJob.cs @@ -2,19 +2,26 @@ using Microsoft.Extensions.Options; using System.Threading.Tasks; using Volo.Abp.Auditing; +using Volo.Abp.MultiTenancy; namespace LINGYUN.Abp.BackgroundTasks.Internal; [DisableAuditing] -internal class BackgroundCleaningJob : IJobRunnable +public class BackgroundCleaningJob : IJobRunnable { public virtual async Task ExecuteAsync(JobRunnableContext context) { var options = context.ServiceProvider.GetRequiredService>().Value; var store = context.ServiceProvider.GetRequiredService(); + var currentTenant = context.ServiceProvider.GetRequiredService(); - await store.CleanupAsync( - options.MaxJobCleanCount, - options.JobExpiratime); + context.TryGetMultiTenantId(out var tenantId); + + using (currentTenant.Change(tenantId)) + { + await store.CleanupAsync( + options.MaxJobCleanCount, + options.JobExpiratime); + } } } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundKeepAliveJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundKeepAliveJob.cs index d0cd143c0..bc2c7ecef 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundKeepAliveJob.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundKeepAliveJob.cs @@ -6,7 +6,7 @@ using Volo.Abp.Auditing; namespace LINGYUN.Abp.BackgroundTasks.Internal; [DisableAuditing] -internal class BackgroundKeepAliveJob : IJobRunnable +public class BackgroundKeepAliveJob : IJobRunnable { public virtual async Task ExecuteAsync(JobRunnableContext context) { diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundPollingJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundPollingJob.cs index c6209e876..211a8d9ff 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundPollingJob.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundPollingJob.cs @@ -3,32 +3,36 @@ using Microsoft.Extensions.Options; using System.Linq; using System.Threading.Tasks; using Volo.Abp.Auditing; +using Volo.Abp.MultiTenancy; namespace LINGYUN.Abp.BackgroundTasks.Internal; [DisableAuditing] -internal class BackgroundPollingJob : IJobRunnable +public class BackgroundPollingJob : IJobRunnable { public virtual async Task ExecuteAsync(JobRunnableContext context) { var options = context.ServiceProvider.GetRequiredService>().Value; var store = context.ServiceProvider.GetRequiredService(); + var currentTenant = context.ServiceProvider.GetRequiredService(); - // TODO: 如果积压有大量持续性任务, 可能后面的队列无法被检索到 - // 尽量让任务重复次数在可控范围内 - // 需要借助队列提供者来持久化已入队任务 - var waitingJobs = await store.GetWaitingListAsync(options.MaxJobFetchCount); + context.TryGetMultiTenantId(out var tenantId); - if (!waitingJobs.Any()) + using (currentTenant.Change(tenantId)) { - return; - } + var waitingJobs = await store.GetWaitingListAsync(options.MaxJobFetchCount); - var jobScheduler = context.ServiceProvider.GetRequiredService(); + if (!waitingJobs.Any()) + { + return; + } - foreach (var job in waitingJobs) - { - await jobScheduler.QueueAsync(job); + var jobScheduler = context.ServiceProvider.GetRequiredService(); + + foreach (var job in waitingJobs) + { + await jobScheduler.QueueAsync(job); + } } } } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/DefaultBackgroundWorker.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/DefaultBackgroundWorker.cs index adce084cb..51b74a9e7 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/DefaultBackgroundWorker.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/DefaultBackgroundWorker.cs @@ -25,9 +25,12 @@ internal class DefaultBackgroundWorker : BackgroundService protected async override Task ExecuteAsync(CancellationToken stoppingToken) { + // 仅轮询宿主端 await QueuePollingJob(); - await QueueKeepAliveJob(); await QueueCleaningJob(); + + // 周期性任务改为手动入队 + // await QueueKeepAliveJob(); } private async Task QueueKeepAliveJob() @@ -54,7 +57,7 @@ internal class DefaultBackgroundWorker : BackgroundService { Id = Guid.Parse("8F50C5D9-5691-4B99-A52B-CABD91D93C89"), Name = nameof(BackgroundKeepAliveJob), - Group = "Default", + Group = "KeepAlive", Description = "Add periodic tasks", Args = new Dictionary(), Status = JobStatus.Running, @@ -74,7 +77,7 @@ internal class DefaultBackgroundWorker : BackgroundService { Id = Guid.Parse("C51152E9-F0B8-4252-8352-283BE46083CC"), Name = nameof(BackgroundPollingJob), - Group = "Default", + Group = "Polling", Description = "Polling tasks to be executed", Args = new Dictionary(), Status = JobStatus.Running, @@ -94,7 +97,7 @@ internal class DefaultBackgroundWorker : BackgroundService { Id = Guid.Parse("AAAF8783-FA06-4CF9-BDCA-11140FB2478F"), Name = nameof(BackgroundCleaningJob), - Group = "Default", + Group = "Cleaning", Description = "Cleaning tasks to be executed", Args = new Dictionary(), Status = JobStatus.Running, diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobStore.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobStore.cs index a7f230939..89d565877 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobStore.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobStore.cs @@ -131,7 +131,8 @@ public class BackgroundJobStore : IJobStore, ITransientDependency eventData.Type.Name, eventData.Group, eventData.Name, - eventData.RunTime) + eventData.RunTime, + eventData.TenantId) { JobId = eventData.Key }; diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/EventBus/Handlers/TenantSynchronizer.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/EventBus/Handlers/TenantSynchronizer.cs new file mode 100644 index 000000000..ffce4bc69 --- /dev/null +++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/EventBus/Handlers/TenantSynchronizer.cs @@ -0,0 +1,140 @@ +using LINGYUN.Abp.BackgroundTasks; +using LINGYUN.Abp.BackgroundTasks.Internal; +using LINGYUN.Abp.Data.DbMigrator; +using LINGYUN.Abp.MultiTenancy; +using LY.MicroService.TaskManagement.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.MultiTenancy; +using Volo.Abp.TenantManagement; +using Volo.Abp.Uow; + +namespace LY.MicroService.TaskManagement.EventBus.Handlers +{ + public class TenantSynchronizer : + IDistributedEventHandler, + IDistributedEventHandler>, + ITransientDependency + { + protected ILogger Logger { get; } + + protected ICurrentTenant CurrentTenant { get; } + protected IUnitOfWorkManager UnitOfWorkManager { get; } + protected IDbSchemaMigrator DbSchemaMigrator { get; } + protected AbpBackgroundTasksOptions Options { get; } + protected IJobScheduler JobScheduler { get; } + public TenantSynchronizer( + ICurrentTenant currentTenant, + IUnitOfWorkManager unitOfWorkManager, + IDbSchemaMigrator dbSchemaMigrator, + IOptions options, + IJobScheduler jobScheduler, + ILogger logger) + { + CurrentTenant = currentTenant; + UnitOfWorkManager = unitOfWorkManager; + DbSchemaMigrator = dbSchemaMigrator; + JobScheduler = jobScheduler; + Options = options.Value; + + Logger = logger; + } + + public async Task HandleEventAsync(EntityDeletedEto eventData) + { + // 租户删除时移除轮询作业 + var pollingJob = BuildPollingJobInfo(eventData.Entity.Id, eventData.Entity.Name); + await JobScheduler.RemoveAsync(pollingJob); + + var cleaningJob = BuildCleaningJobInfo(eventData.Entity.Id, eventData.Entity.Name); + await JobScheduler.RemoveAsync(cleaningJob); + } + + public async Task HandleEventAsync(CreateEventData eventData) + { + await MigrateAsync(eventData); + + // 持久层介入之后提供对于租户的后台工作者轮询作业 + await QueueBackgroundJobAsync(eventData); + } + + private async Task QueueBackgroundJobAsync(CreateEventData eventData) + { + var pollingJob = BuildPollingJobInfo(eventData.Id, eventData.Name); + await JobScheduler.QueueAsync(pollingJob); + + var cleaningJob = BuildCleaningJobInfo(eventData.Id, eventData.Name); + await JobScheduler.QueueAsync(cleaningJob); + } + + private async Task MigrateAsync(CreateEventData eventData) + { + using (var unitOfWork = UnitOfWorkManager.Begin()) + { + using (CurrentTenant.Change(eventData.Id, eventData.Name)) + { + Logger.LogInformation("Migrating the new tenant database with localization.."); + // 迁移租户数据 + await DbSchemaMigrator.MigrateAsync( + (connectionString, builder) => + { + builder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)); + + return new TaskManagementMigrationsDbContext(builder.Options); + }); + await unitOfWork.SaveChangesAsync(); + + Logger.LogInformation("Migrated the new tenant database with localization."); + } + } + } + + private JobInfo BuildPollingJobInfo(Guid tenantId, string tenantName) + { + return new JobInfo + { + Id = tenantId, + Name = nameof(BackgroundPollingJob), + Group = "Polling", + Description = "Polling tasks to be executed", + Args = new Dictionary() { { nameof(JobInfo.TenantId), tenantId } }, + Status = JobStatus.Running, + BeginTime = DateTime.Now, + CreationTime = DateTime.Now, + Cron = Options.JobFetchCronExpression, + JobType = JobType.Period, + Priority = JobPriority.High, + LockTimeOut = Options.JobFetchLockTimeOut, + TenantId = tenantId, + Type = typeof(BackgroundPollingJob).AssemblyQualifiedName, + }; + } + + private JobInfo BuildCleaningJobInfo(Guid tenantId, string tenantName) + { + return new JobInfo + { + Id = tenantId, + Name = nameof(BackgroundCleaningJob), + Group = "Cleaning", + Description = "Cleaning tasks to be executed", + Args = new Dictionary() { { nameof(JobInfo.TenantId), tenantId } }, + Status = JobStatus.Running, + BeginTime = DateTime.Now, + CreationTime = DateTime.Now, + Cron = Options.JobCleanCronExpression, + JobType = JobType.Period, + Priority = JobPriority.High, + TenantId = tenantId, + Type = typeof(BackgroundCleaningJob).AssemblyQualifiedName, + }; + } + } +} 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 3ce7471c7..81ce97bee 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 @@ -19,12 +19,16 @@ + + + all runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -50,6 +54,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.Configure.cs index 292466017..f562f6796 100644 --- a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.Configure.cs @@ -12,6 +12,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.OpenApi.Models; using StackExchange.Redis; using System; +using System.Collections.Generic; +using System.Collections.Specialized; using System.Text.Encodings.Web; using System.Text.Unicode; using Volo.Abp; @@ -22,7 +24,10 @@ using Volo.Abp.Json; using Volo.Abp.Json.SystemTextJson; using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; +using Volo.Abp.Quartz; using Volo.Abp.VirtualFileSystem; +using Quartz; +using DotNetCore.CAP; namespace LY.MicroService.TaskManagement; @@ -41,6 +46,51 @@ public partial class TaskManagementHttpApiHostModule }); } + private void PreConfigureCAP(IConfiguration configuration) + { + PreConfigure(options => + { + options + .UseMySql(mySqlOptions => + { + configuration.GetSection("CAP:MySql").Bind(mySqlOptions); + }) + .UseRabbitMQ(rabbitMQOptions => + { + configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions); + }) + .UseDashboard(); + }); + } + + private void PreConfigureQuartz(IConfiguration configuration) + { + PreConfigure(options => + { + // 如果使用持久化存储, 则配置quartz持久层 + if (configuration.GetSection("Quartz:UsePersistentStore").Get()) + { + var settings = configuration.GetSection("Quartz:Properties").Get>(); + if (settings != null) + { + foreach (var setting in settings) + { + options.Properties[setting.Key] = setting.Value; + } + } + + options.Configurator += (config) => + { + config.UsePersistentStore(store => + { + store.UseProperties = false; + store.UseJsonSerializer(); + }); + }; + } + }); + } + private void ConfigureDistributedLock(IServiceCollection services, IConfiguration configuration) { var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); 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 44bd38542..dc3a8282f 100644 --- a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs @@ -3,6 +3,7 @@ using LINGYUN.Abp.BackgroundTasks.ExceptionHandling; using LINGYUN.Abp.BackgroundTasks.Jobs; using LINGYUN.Abp.BackgroundTasks.Quartz; using LINGYUN.Abp.Data.DbMigrator; +using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; using LINGYUN.Abp.MultiTenancy.DbFinder; @@ -57,6 +58,7 @@ namespace LY.MicroService.TaskManagement; typeof(AbpSettingManagementEntityFrameworkCoreModule), typeof(AbpTenantManagementEntityFrameworkCoreModule), typeof(AbpLocalizationManagementEntityFrameworkCoreModule), + typeof(AbpCAPEventBusModule), typeof(AbpDataDbMigratorModule), typeof(AbpCachingStackExchangeRedisModule), typeof(AbpAspNetCoreMvcModule), @@ -67,7 +69,11 @@ public partial class TaskManagementHttpApiHostModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { + var configuration = context.Services.GetConfiguration(); + PreConfigureApp(); + PreConfigureCAP(configuration); + PreConfigureQuartz(configuration); } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.json index 25b1a9c80..13e0b79cd 100644 --- a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.json +++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.json @@ -31,6 +31,19 @@ "VirtualHost": "/" } }, + "Quartz": { + "UsePersistentStore": false, + "Properties": { + "quartz.jobStore.dataSource": "tkm", + "quartz.jobStore.type": "Quartz.Impl.AdoJobStore.JobStoreTX,Quartz", + "quartz.jobStore.driverDelegateType": "Quartz.Impl.AdoJobStore.MySQLDelegate,Quartz", + "quartz.dataSource.tkm.connectionString": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", + "quartz.dataSource.tkm.connectionStringName": "TaskManagement", + "quartz.dataSource.tkm.provider": "MySqlConnector", + "quartz.jobStore.clustered": "true", + "quartz.serializer.type": "json" + } + }, "ConnectionStrings": { "Default": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", "TaskManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456",