From 2f90d90c69dfda37ac6a56e5216c60a72450a44c Mon Sep 17 00:00:00 2001 From: cKey <35512826+colinin@users.noreply.github.com> Date: Tue, 5 Apr 2022 17:11:39 +0800 Subject: [PATCH] feat: the job scheduler does not need to centralize processing --- .../AbpBackgroundTasksOptions.cs | 4 + .../LINGYUN/Abp/BackgroundTasks/JobInfo.cs | 4 + .../Quartz/QuartzJobExecutorProvider.cs | 2 + .../Quartz/QuartzTriggerListener.cs | 30 ++- .../TaskManagementJobPublisher.cs | 8 +- .../BackgroundTasks/BackgroundJobManager.cs | 6 +- .../BackgroundWorkerAdapter.cs | 8 - .../BackgroundWorkerManager.cs | 20 +- .../Internal/DefaultBackgroundWorker.cs | 2 + .../BackgroundJobInfoCreateDto.cs | 3 + .../BackgroundJobInfoAppService.cs | 14 +- .../TaskManagement/BackgroundJobInfoConsts.cs | 1 + .../Abp/TaskManagement/BackgroundJobInfo.cs | 7 +- .../TaskManagement/BackgroundJobManager.cs | 9 +- .../Abp/TaskManagement/BackgroundJobStore.cs | 19 +- .../IBackgroundJobInfoRepository.cs | 6 + .../EfCoreBackgroundJobInfoRepository.cs | 16 +- ...agementDbContextModelCreatingExtensions.cs | 3 + .../LINGYUN.Abp.Webhooks.csproj | 2 +- .../LINGYUN/Abp/Webhooks/AbpWebhooksModule.cs | 4 +- .../BackgroundWorker/WebhookSenderJob.cs | 18 +- .../LINGYUN/Abp/Webhooks/WebhookDefinition.cs | 10 - .../LINGYUN/Abp/Webhooks/WebhookSenderArgs.cs | 5 + ...odeName-With-BackgroundJobInfo.Designer.cs | 213 ++++++++++++++++++ ...d-Field-NodeName-With-BackgroundJobInfo.cs | 27 +++ ...agementMigrationsDbContextModelSnapshot.cs | 5 + ...ice.WebhooksManagement.HttpApi.Host.csproj | 14 +- ...ksManagementHttpApiHostModule.Configure.cs | 40 ++++ .../WebhooksManagementHttpApiHostModule.cs | 9 +- .../appsettings.Development.json | 15 ++ 30 files changed, 452 insertions(+), 72 deletions(-) create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220405072809_Add-Field-NodeName-With-BackgroundJobInfo.Designer.cs create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220405072809_Add-Field-NodeName-With-BackgroundJobInfo.cs diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs index 3438939de..2efcb8f5f 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs @@ -70,6 +70,10 @@ public class AbpBackgroundTasksOptions /// 轮询任务也属于一个后台任务, 需要对每一次轮询加锁,防止重复任务入库 /// public int JobFetchLockTimeOut { get; set; } + /// + /// 指定运行节点 + /// + public string NodeName { get; set; } public AbpBackgroundTasksOptions() { JobFetchEnabled = true; diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobInfo.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobInfo.cs index 46f7ab78c..98842ec17 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobInfo.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobInfo.cs @@ -109,6 +109,10 @@ public class JobInfo /// 0或更小不生效 /// public int LockTimeOut { get; set; } + /// + /// 指定运行节点 + /// + public string NodeName { get; set; } public int GetCanBeTriggered() { 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 26acdca4e..b05185607 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 @@ -47,6 +47,8 @@ public class QuartzJobExecutorProvider : IQuartzJobExecutorProvider, ISingletonD var jobBuilder = JobBuilder.Create(jobType) .WithIdentity(KeyBuilder.CreateJobKey(job)) .WithDescription(job.Description); + // 多节点任务需要 + jobBuilder.UsingJobData(nameof(JobInfo.NodeName), job.NodeName); // 查询任务需要 jobBuilder.UsingJobData(nameof(JobInfo.Id), job.Id); // 有些场景需要 diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzTriggerListener.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzTriggerListener.cs index 8bd37d8d7..29c095e47 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzTriggerListener.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzTriggerListener.cs @@ -1,8 +1,12 @@ -using Quartz; +using Microsoft.Extensions.Options; +using Quartz; using Quartz.Listener; using System.Threading; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; +using System; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; namespace LINGYUN.Abp.BackgroundTasks.Quartz; @@ -12,12 +16,19 @@ public class QuartzTriggerListener : TriggerListenerSupport, ISingletonDependenc public override string Name => "QuartzTriggerListener"; + public ILogger Logger { protected get; set; } + + protected AbpBackgroundTasksOptions Options { get; } protected IJobLockProvider JobLockProvider { get; } public QuartzTriggerListener( - IJobLockProvider jobLockProvider) + IJobLockProvider jobLockProvider, + IOptions options) { JobLockProvider = jobLockProvider; + Options = options.Value; + + Logger = NullLogger.Instance; } public override async Task VetoJobExecution( @@ -25,12 +36,25 @@ public class QuartzTriggerListener : TriggerListenerSupport, ISingletonDependenc IJobExecutionContext context, CancellationToken cancellationToken = default) { + if (!Options.NodeName.IsNullOrWhiteSpace()) + { + context.MergedJobDataMap.TryGetValue(nameof(JobInfo.NodeName), out var jobNode); + if (!Equals(Options.NodeName, jobNode)) + { + Logger.LogDebug("the job does not belong to the current node and will be ignored by the scheduler."); + return true; + } + } context.MergedJobDataMap.TryGetValue(nameof(JobInfo.Id), out var jobId); context.MergedJobDataMap.TryGetValue(nameof(JobInfo.LockTimeOut), out var lockTime); if (jobId != null && lockTime != null && int.TryParse(lockTime.ToString(), out var time) && time > 0) { // 传递令牌将清除本次锁, 那并无意义 - return !await JobLockProvider.TryLockAsync(NormalizeKey(context, jobId), time); + if (!await JobLockProvider.TryLockAsync(NormalizeKey(context, jobId), time)) + { + Logger.LogDebug("The exclusive job is already in use by another scheduler. Ignore this schedule."); + return true; + } } return false; diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.TaskManagement/LINGYUN/Abp/BackgroundTasks/TaskManagement/TaskManagementJobPublisher.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.TaskManagement/LINGYUN/Abp/BackgroundTasks/TaskManagement/TaskManagementJobPublisher.cs index 074301dc9..e1ff1f704 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.TaskManagement/LINGYUN/Abp/BackgroundTasks/TaskManagement/TaskManagementJobPublisher.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.TaskManagement/LINGYUN/Abp/BackgroundTasks/TaskManagement/TaskManagementJobPublisher.cs @@ -1,4 +1,5 @@ using LINGYUN.Abp.TaskManagement; +using Microsoft.Extensions.Options; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Data; @@ -8,12 +9,15 @@ namespace LINGYUN.Abp.BackgroundTasks.TaskManagement; public class TaskManagementJobPublisher : IJobPublisher, ITransientDependency { + protected AbpBackgroundTasksOptions Options { get; } protected IBackgroundJobInfoAppService BackgroundJobAppService { get; } public TaskManagementJobPublisher( - IBackgroundJobInfoAppService backgroundJobAppService) + IBackgroundJobInfoAppService backgroundJobAppService, + IOptions options) { BackgroundJobAppService = backgroundJobAppService; + Options = options.Value; } public async virtual Task PublishAsync(JobInfo job, CancellationToken cancellationToken = default) @@ -34,7 +38,9 @@ public class TaskManagementJobPublisher : IJobPublisher, ITransientDependency LockTimeOut = job.LockTimeOut, IsEnabled = true, Name = job.Name, + Source = job.Source, Priority = job.Priority, + NodeName = Options.NodeName, }; await BackgroundJobAppService.CreateAsync(input); diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobManager.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobManager.cs index a81f67921..28f92653a 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobManager.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobManager.cs @@ -20,6 +20,7 @@ public class BackgroundJobManager : IBackgroundJobManager, ITransientDependency protected ICurrentTenant CurrentTenant { get; } protected IGuidGenerator GuidGenerator { get; } protected IJsonSerializer JsonSerializer { get; } + protected AbpBackgroundTasksOptions TasksOptions { get; } protected AbpBackgroundJobOptions Options { get; } public BackgroundJobManager( IClock clock, @@ -28,7 +29,8 @@ public class BackgroundJobManager : IBackgroundJobManager, ITransientDependency ICurrentTenant currentTenant, IGuidGenerator guidGenerator, IJsonSerializer jsonSerializer, - IOptions options) + IOptions options, + IOptions taskOptions) { Clock = clock; JobStore = jobStore; @@ -37,6 +39,7 @@ public class BackgroundJobManager : IBackgroundJobManager, ITransientDependency GuidGenerator = guidGenerator; JsonSerializer = jsonSerializer; Options = options.Value; + TasksOptions = taskOptions.Value; } public virtual async Task EnqueueAsync( @@ -74,6 +77,7 @@ public class BackgroundJobManager : IBackgroundJobManager, ITransientDependency CreationTime = Clock.Now, // 确保不会被轮询入队 Status = JobStatus.None, + NodeName = TasksOptions.NodeName, Type = typeof(BackgroundJobAdapter).AssemblyQualifiedName, }; diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundWorkerAdapter.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundWorkerAdapter.cs index 4797acaca..e45e9210f 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundWorkerAdapter.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundWorkerAdapter.cs @@ -4,18 +4,13 @@ using System.Reflection; using System.Threading.Tasks; using Volo.Abp.BackgroundWorkers; using Volo.Abp.DynamicProxy; -using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; -using Volo.Abp.Timing; namespace LINGYUN.Abp.BackgroundTasks; public class BackgroundWorkerAdapter : BackgroundWorkerBase, IBackgroundWorkerRunnable where TWorker : IBackgroundWorker { - protected IClock Clock => LazyServiceProvider.LazyGetRequiredService(); - protected ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService(); - private readonly MethodInfo _doWorkAsyncMethod; private readonly MethodInfo _doWorkMethod; @@ -70,12 +65,10 @@ public class BackgroundWorkerAdapter : BackgroundWorkerBase, IBackgroun return new JobInfo { Id = workerType.FullName, - TenantId = CurrentTenant.Id, Name = workerType.FullName, Group = "BackgroundWorkers", Priority = JobPriority.Normal, Source = JobSource.System, - BeginTime = Clock.Now, Args = jobArgs, Description = "From the framework background workers", JobType = JobType.Persistent, @@ -83,7 +76,6 @@ public class BackgroundWorkerAdapter : BackgroundWorkerBase, IBackgroun MaxCount = 0, // TODO: 可配置 MaxTryCount = 10, - CreationTime = Clock.Now, // 确保不会被轮询入队 Status = JobStatus.None, Type = typeof(BackgroundWorkerAdapter).AssemblyQualifiedName, diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundWorkerManager.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundWorkerManager.cs index fb40f5135..366aae3da 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundWorkerManager.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundWorkerManager.cs @@ -1,24 +1,36 @@ -using System; +using Microsoft.Extensions.Options; +using System; using System.Threading; using System.Threading.Tasks; using Volo.Abp.BackgroundWorkers; using Volo.Abp.DependencyInjection; using Volo.Abp.DynamicProxy; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Timing; namespace LINGYUN.Abp.BackgroundTasks; [Dependency(ReplaceServices = true)] public class BackgroundWorkerManager : IBackgroundWorkerManager, ISingletonDependency { + protected IClock Clock { get; } protected IJobStore JobStore { get; } protected IJobPublisher JobPublisher { get; } + protected ICurrentTenant CurrentTenant { get; } + protected AbpBackgroundTasksOptions Options { get; } public BackgroundWorkerManager( + IClock clock, IJobStore jobStore, - IJobPublisher jobPublisher) + IJobPublisher jobPublisher, + ICurrentTenant currentTenant, + IOptions options) { + Clock = clock; JobStore = jobStore; JobPublisher = jobPublisher; + CurrentTenant = currentTenant; + Options = options.Value; } public async Task AddAsync(IBackgroundWorker worker) @@ -34,6 +46,10 @@ public class BackgroundWorkerManager : IBackgroundWorkerManager, ISingletonDepen return; } + jobInfo.NodeName = Options.NodeName; + jobInfo.BeginTime = Clock.Now; + jobInfo.CreationTime = Clock.Now; + jobInfo.TenantId = CurrentTenant.Id; // 存储状态 await JobStore.StoreAsync(jobInfo); 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 a8920f34e..b38030783 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 @@ -64,6 +64,7 @@ internal class DefaultBackgroundWorker : BackgroundService Priority = JobPriority.High, Source = JobSource.System, LockTimeOut = _options.JobFetchLockTimeOut, + NodeName = _options.NodeName, Type = typeof(BackgroundPollingJob).AssemblyQualifiedName, }; } @@ -84,6 +85,7 @@ internal class DefaultBackgroundWorker : BackgroundService JobType = JobType.Period, Priority = JobPriority.High, Source = JobSource.System, + NodeName = _options.NodeName, Type = typeof(BackgroundCleaningJob).AssemblyQualifiedName, }; } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoCreateDto.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoCreateDto.cs index a391aa228..2706086d6 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoCreateDto.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoCreateDto.cs @@ -25,6 +25,9 @@ public class BackgroundJobInfoCreateDto : BackgroundJobInfoCreateOrUpdateDto [Required] [DynamicStringLength(typeof(BackgroundJobInfoConsts), nameof(BackgroundJobInfoConsts.MaxTypeLength))] public string Type { get; set; } + + [DynamicStringLength(typeof(BackgroundJobInfoConsts), nameof(BackgroundJobInfoConsts.MaxNodeNameLength))] + public string NodeName { get; set; } /// /// 开始时间 /// diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobInfoAppService.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobInfoAppService.cs index 01f54f01a..c3a36539c 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobInfoAppService.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobInfoAppService.cs @@ -1,6 +1,7 @@ using LINGYUN.Abp.BackgroundTasks; using LINGYUN.Abp.TaskManagement.Permissions; using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -13,15 +14,18 @@ namespace LINGYUN.Abp.TaskManagement; [Authorize(TaskManagementPermissions.BackgroundJobs.Default)] public class BackgroundJobInfoAppService : TaskManagementApplicationService, IBackgroundJobInfoAppService { + protected AbpBackgroundTasksOptions Options { get; } protected BackgroundJobManager BackgroundJobManager { get; } protected IBackgroundJobInfoRepository BackgroundJobInfoRepository { get; } public BackgroundJobInfoAppService( BackgroundJobManager backgroundJobManager, - IBackgroundJobInfoRepository backgroundJobInfoRepository) + IBackgroundJobInfoRepository backgroundJobInfoRepository, + IOptions options) { BackgroundJobManager = backgroundJobManager; BackgroundJobInfoRepository = backgroundJobInfoRepository; + Options = options.Value; } [Authorize(TaskManagementPermissions.BackgroundJobs.Create)] @@ -47,16 +51,14 @@ public class BackgroundJobInfoAppService : TaskManagementApplicationService, IBa input.Source, input.MaxCount, input.MaxTryCount, + input.NodeName ?? Options.NodeName, CurrentTenant.Id); UpdateByInput(backgroundJobInfo, input); - await BackgroundJobInfoRepository.InsertAsync(backgroundJobInfo, autoSave: true); + await BackgroundJobManager.CreateAsync(backgroundJobInfo); - if (backgroundJobInfo.IsEnabled && backgroundJobInfo.JobType == JobType.Period) - { - await BackgroundJobManager.QueueAsync(backgroundJobInfo); - } + await CurrentUnitOfWork.SaveChangesAsync(); return ObjectMapper.Map(backgroundJobInfo); } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/BackgroundJobInfoConsts.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/BackgroundJobInfoConsts.cs index 733823f4c..1d3ad97da 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/BackgroundJobInfoConsts.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/BackgroundJobInfoConsts.cs @@ -5,6 +5,7 @@ public static class BackgroundJobInfoConsts public static int MaxCronLength { get; set; } = 50; public static int MaxNameLength { get; set; } = 100; public static int MaxGroupLength { get; set; } = 50; + public static int MaxNodeNameLength { get; set; } = 128; public static int MaxTypeLength { get; set; } = 1000; public static int MaxDescriptionLength { get; set; } = 255; public static int MaxResultLength { get; set; } = 1000; diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobInfo.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobInfo.cs index bb202421c..6c7342c94 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobInfo.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobInfo.cs @@ -107,7 +107,10 @@ public class BackgroundJobInfo : AuditedAggregateRoot, IMultiTenant /// 连续失败且不会再次执行 /// public virtual bool IsAbandoned { get; set; } - + /// + /// 指定作业运行节点 + /// + public virtual string NodeName { get; protected set; } protected BackgroundJobInfo() { } public BackgroundJobInfo( @@ -122,6 +125,7 @@ public class BackgroundJobInfo : AuditedAggregateRoot, IMultiTenant JobSource source = JobSource.None, int maxCount = 0, int maxTryCount = 50, + string nodeName = null, Guid? tenantId = null) : base(id) { Name = Check.NotNullOrWhiteSpace(name, nameof(name), BackgroundJobInfoConsts.MaxNameLength); @@ -134,6 +138,7 @@ public class BackgroundJobInfo : AuditedAggregateRoot, IMultiTenant MaxCount = maxCount; MaxTryCount = maxTryCount; + NodeName = Check.Length(nodeName, nameof(nodeName), BackgroundJobInfoConsts.MaxNodeNameLength); TenantId = tenantId; Status = JobStatus.Running; diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobManager.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobManager.cs index 4dd9a07f4..19ea64aab 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobManager.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobManager.cs @@ -1,7 +1,6 @@ using LINGYUN.Abp.BackgroundTasks; -using System.Threading.Tasks; using System.Collections.Generic; -using Volo.Abp; +using System.Threading.Tasks; using Volo.Abp.Domain.Services; using Volo.Abp.ObjectMapping; using Volo.Abp.Uow; @@ -34,12 +33,6 @@ public class BackgroundJobManager : DomainService if (jobInfo.IsEnabled && jobInfo.JobType == JobType.Period) { var job = ObjectMapper.Map(jobInfo); - if (await JobScheduler.ExistsAsync(job)) - { - throw new BusinessException(TaskManagementErrorCodes.JobNameAlreadyExists) - .WithData("Group", job.Group) - .WithData("Name", job.Name); - } UnitOfWorkManager.Current.OnCompleted(async () => { await JobScheduler.QueueAsync(job); 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 b48cd20a7..8c6df46ab 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 @@ -1,9 +1,9 @@ using LINGYUN.Abp.BackgroundTasks; +using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; using Volo.Abp.ObjectMapping; @@ -19,28 +19,32 @@ public class BackgroundJobStore : IJobStore, ITransientDependency protected IBackgroundJobInfoRepository JobInfoRepository { get; } protected IBackgroundJobLogRepository JobLogRepository { get; } + protected AbpBackgroundTasksOptions Options { get; } + public BackgroundJobStore( IObjectMapper objectMapper, ICurrentTenant currentTenant, IBackgroundJobInfoRepository jobInfoRepository, - IBackgroundJobLogRepository jobLogRepository) + IBackgroundJobLogRepository jobLogRepository, + IOptions options) { ObjectMapper = objectMapper; CurrentTenant = currentTenant; JobInfoRepository = jobInfoRepository; JobLogRepository = jobLogRepository; + Options = options.Value; } public async virtual Task> GetAllPeriodTasksAsync(CancellationToken cancellationToken = default) { - var jobInfos = await JobInfoRepository.GetAllPeriodTasksAsync(cancellationToken); + var jobInfos = await JobInfoRepository.GetAllPeriodTasksAsync(Options.NodeName, cancellationToken); return ObjectMapper.Map, List>(jobInfos); } public async virtual Task> GetWaitingListAsync(int maxResultCount, CancellationToken cancellationToken = default) { - var jobInfos = await JobInfoRepository.GetWaitingListAsync(maxResultCount, cancellationToken); + var jobInfos = await JobInfoRepository.GetWaitingListAsync(Options.NodeName, maxResultCount, cancellationToken); return ObjectMapper.Map, List>(jobInfos); } @@ -142,9 +146,10 @@ public class BackgroundJobStore : IJobStore, ITransientDependency CancellationToken cancellationToken = default) { var jobs = await JobInfoRepository.GetExpiredJobsAsync( - maxResultCount, - jobExpiratime, - cancellationToken); + Options.NodeName, + maxResultCount, + jobExpiratime, + cancellationToken); await JobInfoRepository.DeleteManyAsync(jobs, cancellationToken: cancellationToken); } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/IBackgroundJobInfoRepository.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/IBackgroundJobInfoRepository.cs index 603d66c1f..f02f59794 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/IBackgroundJobInfoRepository.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/IBackgroundJobInfoRepository.cs @@ -27,11 +27,13 @@ public interface IBackgroundJobInfoRepository : IRepository /// 获取过期任务列表 /// + /// /// /// /// /// Task> GetExpiredJobsAsync( + string nodeName, int maxResultCount, TimeSpan jobExpiratime, CancellationToken cancellationToken = default); @@ -39,16 +41,20 @@ public interface IBackgroundJobInfoRepository : IRepository + /// /// Task> GetAllPeriodTasksAsync( + string nodeName, CancellationToken cancellationToken = default); /// /// 获取等待入队的任务列表 /// + /// /// /// /// Task> GetWaitingListAsync( + string nodeName, int maxResultCount, CancellationToken cancellationToken = default); /// diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/EfCoreBackgroundJobInfoRepository.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/EfCoreBackgroundJobInfoRepository.cs index 073a75e92..9b86a16e4 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/EfCoreBackgroundJobInfoRepository.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/EfCoreBackgroundJobInfoRepository.cs @@ -69,12 +69,14 @@ public class EfCoreBackgroundJobInfoRepository : Result = x.Result, TriggerCount = x.TriggerCount, TryCount = x.TryCount, - Type = x.Type + Type = x.Type, + NodeName = x.NodeName, }) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); } public virtual async Task> GetExpiredJobsAsync( + string nodeName, int maxResultCount, TimeSpan jobExpiratime, CancellationToken cancellationToken = default) @@ -82,6 +84,7 @@ public class EfCoreBackgroundJobInfoRepository : var expiratime = Clock.Now - jobExpiratime; return await (await GetDbSetAsync()) + .Where(x => x.NodeName == nodeName) .Where(x => x.Status == JobStatus.Completed && DateTime.Compare(x.LastRunTime.Value, expiratime) <= 0) .OrderBy(x => x.CreationTime) @@ -89,11 +92,14 @@ public class EfCoreBackgroundJobInfoRepository : .ToListAsync(GetCancellationToken(cancellationToken)); } - public virtual async Task> GetAllPeriodTasksAsync(CancellationToken cancellationToken = default) + public virtual async Task> GetAllPeriodTasksAsync( + string nodeName, + CancellationToken cancellationToken = default) { var status = new JobStatus[] { JobStatus.Running, JobStatus.FailedRetry }; return await (await GetDbSetAsync()) + .Where(x => x.NodeName == nodeName) .Where(x => x.IsEnabled && !x.IsAbandoned) .Where(x => x.JobType == JobType.Period && status.Contains(x.Status)) .Where(x => (x.MaxCount == 0 || x.TriggerCount < x.MaxCount) || (x.MaxTryCount == 0 || x.TryCount < x.MaxTryCount)) @@ -116,12 +122,16 @@ public class EfCoreBackgroundJobInfoRepository : .ToListAsync(GetCancellationToken(cancellationToken)); } - public virtual async Task> GetWaitingListAsync(int maxResultCount, CancellationToken cancellationToken = default) + public virtual async Task> GetWaitingListAsync( + string nodeName, + int maxResultCount, + CancellationToken cancellationToken = default) { var now = Clock.Now; var status = new JobStatus[] { JobStatus.Running, JobStatus.FailedRetry }; return await (await GetDbSetAsync()) + .Where(x => x.NodeName == nodeName) .Where(x => x.IsEnabled && !x.IsAbandoned) .Where(x => x.JobType != JobType.Period && status.Contains(x.Status)) .Where(x => (x.MaxCount == 0 || x.TriggerCount < x.MaxCount) || (x.MaxTryCount == 0 || x.TryCount < x.MaxTryCount)) diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementDbContextModelCreatingExtensions.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementDbContextModelCreatingExtensions.cs index 36c6ca547..2a677e917 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementDbContextModelCreatingExtensions.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementDbContextModelCreatingExtensions.cs @@ -47,6 +47,9 @@ public static class TaskManagementDbContextModelCreatingExtensions b.Property(p => p.Result) .HasColumnName(nameof(BackgroundJobInfo.Result)) .HasMaxLength(BackgroundJobInfoConsts.MaxResultLength); + b.Property(p => p.NodeName) + .HasColumnName(nameof(BackgroundJobInfo.NodeName)) + .HasMaxLength(BackgroundJobInfoConsts.MaxNodeNameLength); b.Property(p => p.Args) .HasColumnName(nameof(BackgroundJobInfo.Args)) .HasConversion(new ExtraPropertiesValueConverter(b.Metadata.ClrType)) diff --git a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN.Abp.Webhooks.csproj b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN.Abp.Webhooks.csproj index 2cd64673f..ca6031c7a 100644 --- a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN.Abp.Webhooks.csproj +++ b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN.Abp.Webhooks.csproj @@ -9,7 +9,7 @@ - + diff --git a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/AbpWebhooksModule.cs b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/AbpWebhooksModule.cs index 84798d8d2..0e66d8f81 100644 --- a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/AbpWebhooksModule.cs +++ b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/AbpWebhooksModule.cs @@ -9,9 +9,7 @@ using Volo.Abp.Modularity; namespace LINGYUN.Abp.Webhooks; -//[DependsOn(typeof(AbpBackgroundJobsAbstractionsModule))] -// 防止未引用实现无法发布到后台作业 -[DependsOn(typeof(AbpBackgroundJobsModule))] +[DependsOn(typeof(AbpBackgroundJobsAbstractionsModule))] [DependsOn(typeof(AbpFeaturesModule))] [DependsOn(typeof(AbpGuidsModule))] [DependsOn(typeof(AbpHttpClientModule))] diff --git a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/BackgroundWorker/WebhookSenderJob.cs b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/BackgroundWorker/WebhookSenderJob.cs index b411e3a84..4d18cb209 100644 --- a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/BackgroundWorker/WebhookSenderJob.cs +++ b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/BackgroundWorker/WebhookSenderJob.cs @@ -11,7 +11,6 @@ namespace LINGYUN.Abp.Webhooks.BackgroundWorker public class WebhookSenderJob : AsyncBackgroundJob, ITransientDependency { private readonly IUnitOfWorkManager _unitOfWorkManager; - private readonly IWebhookDefinitionManager _webhookDefinitionManager; private readonly IWebhookSubscriptionManager _webhookSubscriptionManager; private readonly IWebhookSendAttemptStore _webhookSendAttemptStore; private readonly IWebhookSender _webhookSender; @@ -20,14 +19,12 @@ namespace LINGYUN.Abp.Webhooks.BackgroundWorker public WebhookSenderJob( IUnitOfWorkManager unitOfWorkManager, - IWebhookDefinitionManager webhookDefinitionManager, IWebhookSubscriptionManager webhookSubscriptionManager, IWebhookSendAttemptStore webhookSendAttemptStore, IWebhookSender webhookSender, IOptions options) { _unitOfWorkManager = unitOfWorkManager; - _webhookDefinitionManager = webhookDefinitionManager; _webhookSubscriptionManager = webhookSubscriptionManager; _webhookSendAttemptStore = webhookSendAttemptStore; _webhookSender = webhookSender; @@ -36,13 +33,11 @@ namespace LINGYUN.Abp.Webhooks.BackgroundWorker public override async Task ExecuteAsync(WebhookSenderArgs args) { - var webhookDefinition = _webhookDefinitionManager.Get(args.WebhookName); - - if (webhookDefinition.TryOnce) + if (args.TryOnce) { try { - await SendWebhook(args, webhookDefinition); + await SendWebhook(args); } catch (Exception e) { @@ -52,11 +47,11 @@ namespace LINGYUN.Abp.Webhooks.BackgroundWorker } else { - await SendWebhook(args, webhookDefinition); + await SendWebhook(args); } } - private async Task SendWebhook(WebhookSenderArgs args, WebhookDefinition webhookDefinition) + private async Task SendWebhook(WebhookSenderArgs args) { if (args.WebhookEventId == default) { @@ -68,7 +63,7 @@ namespace LINGYUN.Abp.Webhooks.BackgroundWorker return; } - if (!webhookDefinition.TryOnce) + if (!args.TryOnce) { var sendAttemptCount = await _webhookSendAttemptStore.GetSendAttemptCountAsync( args.TenantId, @@ -76,8 +71,7 @@ namespace LINGYUN.Abp.Webhooks.BackgroundWorker args.WebhookSubscriptionId ); - if ((webhookDefinition.MaxSendAttemptCount > 0 && sendAttemptCount > webhookDefinition.MaxSendAttemptCount) || - sendAttemptCount > _options.MaxSendAttemptCount) + if (sendAttemptCount > _options.MaxSendAttemptCount) { return; } diff --git a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/WebhookDefinition.cs b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/WebhookDefinition.cs index 1c1461e8a..88f3a074d 100644 --- a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/WebhookDefinition.cs +++ b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/WebhookDefinition.cs @@ -11,16 +11,6 @@ namespace LINGYUN.Abp.Webhooks /// public string Name { get; } - /// - /// Tries to send webhook only one time without checking to send attempt count - /// - public bool TryOnce { get; set; } - - /// - /// Defined maximum number of sending times - /// - public int MaxSendAttemptCount { get; set; } - /// /// Display name of the webhook. /// Optional. diff --git a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/WebhookSenderArgs.cs b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/WebhookSenderArgs.cs index cb30acbf9..7910ba0b1 100644 --- a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/WebhookSenderArgs.cs +++ b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks/LINGYUN/Abp/Webhooks/WebhookSenderArgs.cs @@ -46,6 +46,11 @@ namespace LINGYUN.Abp.Webhooks /// public IDictionary Headers { get; set; } + /// + /// Tries to send webhook only one time without checking to send attempt count + /// + public bool TryOnce { get; set; } + /// /// True: It sends the exact same data as the parameter to clients. /// diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220405072809_Add-Field-NodeName-With-BackgroundJobInfo.Designer.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220405072809_Add-Field-NodeName-With-BackgroundJobInfo.Designer.cs new file mode 100644 index 000000000..2170291ca --- /dev/null +++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220405072809_Add-Field-NodeName-With-BackgroundJobInfo.Designer.cs @@ -0,0 +1,213 @@ +// +using System; +using LY.MicroService.TaskManagement.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace LY.MicroService.TaskManagement.Migrations +{ + [DbContext(typeof(TaskManagementMigrationsDbContext))] + [Migration("20220405072809_Add-Field-NodeName-With-BackgroundJobInfo")] + partial class AddFieldNodeNameWithBackgroundJobInfo + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) + .HasAnnotation("ProductVersion", "6.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("LINGYUN.Abp.TaskManagement.BackgroundJobInfo", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("Args") + .HasColumnType("longtext") + .HasColumnName("Args"); + + b.Property("BeginTime") + .HasColumnType("datetime(6)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Cron") + .HasMaxLength(50) + .HasColumnType("varchar(50)") + .HasColumnName("Cron"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Description"); + + b.Property("EndTime") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Group") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)") + .HasColumnName("Group"); + + b.Property("Interval") + .HasColumnType("int"); + + b.Property("IsAbandoned") + .HasColumnType("tinyint(1)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("JobType") + .HasColumnType("int"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("LastRunTime") + .HasColumnType("datetime(6)"); + + b.Property("LockTimeOut") + .HasColumnType("int"); + + b.Property("MaxCount") + .HasColumnType("int"); + + b.Property("MaxTryCount") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("Name"); + + b.Property("NextRunTime") + .HasColumnType("datetime(6)"); + + b.Property("NodeName") + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("NodeName"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Result") + .HasMaxLength(1000) + .HasColumnType("varchar(1000)") + .HasColumnName("Result"); + + b.Property("Source") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(-1) + .HasColumnName("Source"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("TriggerCount") + .HasColumnType("int"); + + b.Property("TryCount") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("varchar(1000)") + .HasColumnName("Type"); + + b.HasKey("Id"); + + b.HasIndex("Name", "Group"); + + b.ToTable("TK_BackgroundJobs", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TaskManagement.BackgroundJobLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Exception") + .HasMaxLength(2000) + .HasColumnType("varchar(2000)") + .HasColumnName("Exception"); + + b.Property("JobGroup") + .HasMaxLength(50) + .HasColumnType("varchar(50)") + .HasColumnName("JobGroup"); + + b.Property("JobId") + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("JobId"); + + b.Property("JobName") + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("JobName"); + + b.Property("JobType") + .HasMaxLength(1000) + .HasColumnType("varchar(1000)") + .HasColumnName("JobType"); + + b.Property("Message") + .HasMaxLength(1000) + .HasColumnType("varchar(1000)") + .HasColumnName("Message"); + + b.Property("RunTime") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("JobGroup", "JobName"); + + b.ToTable("TK_BackgroundJobLogs", (string)null); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220405072809_Add-Field-NodeName-With-BackgroundJobInfo.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220405072809_Add-Field-NodeName-With-BackgroundJobInfo.cs new file mode 100644 index 000000000..58d6dd3c2 --- /dev/null +++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220405072809_Add-Field-NodeName-With-BackgroundJobInfo.cs @@ -0,0 +1,27 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace LY.MicroService.TaskManagement.Migrations +{ + public partial class AddFieldNodeNameWithBackgroundJobInfo : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "NodeName", + table: "TK_BackgroundJobs", + type: "varchar(128)", + maxLength: 128, + nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "NodeName", + table: "TK_BackgroundJobs"); + } + } +} diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/TaskManagementMigrationsDbContextModelSnapshot.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/TaskManagementMigrationsDbContextModelSnapshot.cs index 1b6f44954..e77b0f616 100644 --- a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/TaskManagementMigrationsDbContextModelSnapshot.cs +++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/TaskManagementMigrationsDbContextModelSnapshot.cs @@ -111,6 +111,11 @@ namespace LY.MicroService.TaskManagement.Migrations b.Property("NextRunTime") .HasColumnType("datetime(6)"); + b.Property("NodeName") + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("NodeName"); + b.Property("Priority") .HasColumnType("int"); diff --git a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/LY.MicroService.WebhooksManagement.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/LY.MicroService.WebhooksManagement.HttpApi.Host.csproj index 78cda36e2..a2659d4f1 100644 --- a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/LY.MicroService.WebhooksManagement.HttpApi.Host.csproj +++ b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/LY.MicroService.WebhooksManagement.HttpApi.Host.csproj @@ -34,6 +34,7 @@ + @@ -57,11 +58,14 @@ - - - - - + + + + + + + + diff --git a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs index ddb24ddb0..e8269ad2b 100644 --- a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs @@ -1,4 +1,5 @@ using DotNetCore.CAP; +using LINGYUN.Abp.BackgroundTasks; using LINGYUN.Abp.Dapr.Client.DynamicProxying; using LINGYUN.Abp.ExceptionHandling; using LINGYUN.Abp.ExceptionHandling.Emailing; @@ -15,8 +16,10 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.OpenApi.Models; using OpenTelemetry.Resources; using OpenTelemetry.Trace; +using Quartz; using StackExchange.Redis; using System; +using System.Collections.Generic; using System.Text.Encodings.Web; using System.Text.Unicode; using Volo.Abp; @@ -28,6 +31,7 @@ using Volo.Abp.Json; using Volo.Abp.Json.SystemTextJson; using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; +using Volo.Abp.Quartz; using Volo.Abp.Threading; using Volo.Abp.VirtualFileSystem; @@ -76,6 +80,34 @@ public partial class WebhooksManagementHttpApiHostModule }); } + 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 ConfigureDbContext() { // 配置Ef @@ -90,6 +122,14 @@ public partial class WebhooksManagementHttpApiHostModule }); } + private void ConfigureBackgroundTasks() + { + Configure(options => + { + options.NodeName = ApplicationName; + }); + } + private void ConfigureJsonSerializer() { // 解决某些不支持类型的序列化 diff --git a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.cs index fe0d5379e..6ecd3954e 100644 --- a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.cs @@ -1,12 +1,15 @@ using DotNetCore.CAP; using LINGYUN.Abp.AspNetCore.Mvc.Wrapper; using LINGYUN.Abp.AuditLogging.Elasticsearch; +using LINGYUN.Abp.BackgroundTasks.ExceptionHandling; +using LINGYUN.Abp.BackgroundTasks.Quartz; using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; using LINGYUN.Abp.Saas.EntityFrameworkCore; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; +using LINGYUN.Abp.TaskManagement.EntityFrameworkCore; using LINGYUN.Abp.Webhooks.Identity; using LINGYUN.Abp.Webhooks.Saas; using LINGYUN.Abp.WebhooksManagement; @@ -42,6 +45,9 @@ namespace LY.MicroService.WebhooksManagement; typeof(WebhooksManagementEntityFrameworkCoreModule), typeof(AbpWebhooksIdentityModule), typeof(AbpWebhooksSaasModule), + typeof(AbpBackgroundTasksQuartzModule), + typeof(AbpBackgroundTasksExceptionHandlingModule), + typeof(TaskManagementEntityFrameworkCoreModule), typeof(AbpEntityFrameworkCoreMySQLModule), typeof(AbpAspNetCoreAuthenticationJwtBearerModule), typeof(AbpEmailingExceptionHandlingModule), @@ -68,6 +74,7 @@ public partial class WebhooksManagementHttpApiHostModule : AbpModule PreConfigureApp(); PreConfigureFeature(); PreConfigureCAP(configuration); + PreConfigureQuartz(configuration); } public override void ConfigureServices(ServiceConfigurationContext context) @@ -79,6 +86,7 @@ public partial class WebhooksManagementHttpApiHostModule : AbpModule ConfigureDbContext(); ConfigureLocalization(); ConfigureJsonSerializer(); + ConfigureBackgroundTasks(); ConfigureExceptionHandling(); ConfigureVirtualFileSystem(); ConfigureCaching(configuration); @@ -89,7 +97,6 @@ public partial class WebhooksManagementHttpApiHostModule : AbpModule ConfigureDistributedLock(context.Services, configuration); ConfigureSeedWorker(context.Services, hostingEnvironment.IsDevelopment()); ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment()); - context.Services.AddAlwaysAllowAuthorization(); } diff --git a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/appsettings.Development.json index 4a816c0c1..57f18945f 100644 --- a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/appsettings.Development.json +++ b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/appsettings.Development.json @@ -13,6 +13,7 @@ "ConnectionStrings": { "Default": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", "WebhooksManagement": "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", "AbpSaas": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", "AbpFeatureManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", "AbpPermissionManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", @@ -60,6 +61,20 @@ "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", + "quartz.scheduler.instanceName": "webhook" + } + }, "Redis": { "Configuration": "127.0.0.1,defaultDatabase=10", "InstanceName": "LINGYUN.Abp.Application"