From b708afbd883184f9937f11449579cb5c1d99f890 Mon Sep 17 00:00:00 2001
From: cKey <35512826+colinin@users.noreply.github.com>
Date: Sat, 8 Jan 2022 22:36:25 +0800
Subject: [PATCH 01/10] enhance(tasks): add support task management
---
aspnet-core/.editorconfig | 7 +-
aspnet-core/LINGYUN.MicroService.All.sln | 2 +-
.../FodyWeavers.xml | 3 +
.../FodyWeavers.xsd | 30 +++
...UN.Abp.BackgroundTasks.Abstractions.csproj | 15 ++
.../AbpBackgroundTasksAbstractionsModule.cs | 7 +
.../Abp/BackgroundTasks/IJobRunnable.cs | 11 +
.../BackgroundTasks/IJobRunnableExecuter.cs | 12 +
.../Abp/BackgroundTasks/JobEventContext.cs | 17 ++
.../Abp/BackgroundTasks/JobEventData.cs | 90 ++++++++
.../LINGYUN/Abp/BackgroundTasks/JobInfo.cs | 104 +++++++++
.../Abp/BackgroundTasks/JobPriority.cs | 15 ++
.../Abp/BackgroundTasks/JobRunnableContext.cs | 20 ++
.../LINGYUN/Abp/BackgroundTasks/JobStatus.cs | 25 ++
.../LINGYUN/Abp/BackgroundTasks/JobType.cs | 19 ++
.../FodyWeavers.xml | 3 +
.../FodyWeavers.xsd | 30 +++
.../LINGYUN.Abp.BackgroundTasks.Quartz.csproj | 19 ++
.../Quartz/AbpBackgroundTasksQuartzModule.cs | 19 ++
.../Quartz/IQuartzJobExecutorProvider.cs | 12 +
.../Quartz/QuartzJobExecutorProvider.cs | 102 +++++++++
.../Quartz/QuartzJobListener.cs | 144 ++++++++++++
.../Quartz/QuartzJobScheduler.cs | 164 +++++++++++++
.../Quartz/QuartzJobSimpleAdapter.cs | 33 +++
.../Quartz/IJobExecutionContextExtensions.cs | 27 +++
.../README.md | 16 ++
.../FodyWeavers.xml | 3 +
.../FodyWeavers.xsd | 30 +++
.../LINGYUN.Abp.BackgroundTasks.csproj | 22 ++
.../AbpBackgroundTasksModule.cs | 49 ++++
.../AbpBackgroundTasksOptions.cs | 69 ++++++
.../BackgroundTasks/BackgroundJobAdapter.cs | 39 ++++
.../BackgroundTasks/BackgroundJobManager.cs | 82 +++++++
.../LINGYUN/Abp/BackgroundTasks/IJobEvent.cs | 22 ++
.../Abp/BackgroundTasks/IJobEventProvider.cs | 15 ++
.../Abp/BackgroundTasks/IJobScheduler.cs | 72 ++++++
.../LINGYUN/Abp/BackgroundTasks/IJobStore.cs | 27 +++
.../Internal/BackgroundCleaningJob.cs | 18 ++
.../Internal/BackgroundKeepAliveJob.cs | 26 +++
.../Internal/BackgroundPollingJob.cs | 31 +++
.../Internal/DefaultBackgroundWorker.cs | 108 +++++++++
.../Internal/InMemoryJobStore.cs | 87 +++++++
.../Internal/JobEventProvider.cs | 41 ++++
.../Internal/JobExecutedEvent.cs | 60 +++++
.../BackgroundTasks/Internal/JobLogEvent.cs | 26 +++
.../Abp/BackgroundTasks/JobEventBase.cs | 58 +++++
.../BackgroundTasks/JobRunnableExecuter.cs | 55 +++++
.../BackgroundTasks/Primitives/ConsoleJob.cs | 13 ++
.../BackgroundTasks/Primitives/EmailingJob.cs | 14 ++
.../LINGYUN.Abp.BackgroundTasks/README.md | 116 ++++++++++
.../FodyWeavers.xml | 3 +
.../FodyWeavers.xsd | 30 +++
...askManagement.Application.Contracts.csproj | 19 ++
.../BackgroundJobInfoCreateDto.cs | 17 ++
.../BackgroundJobInfoCreateOrUpdateDto.cs | 61 +++++
.../TaskManagement/BackgroundJobInfoDto.cs | 99 ++++++++
.../BackgroundJobInfoGetListInput.cs | 65 ++++++
.../BackgroundJobInfoUpdateDto.cs | 8 +
.../Abp/TaskManagement/BackgroundJobLogDto.cs | 14 ++
.../BackgroundJobLogGetListInput.cs | 36 +++
.../IBackgroundJobInfoAppService.cs | 20 ++
.../IBackgroundJobLogAppService.cs | 11 +
.../Permissions/TaskManagementPermissions.cs | 17 ++
...askManagementApplicationContractsModule.cs | 10 +
.../FodyWeavers.xml | 3 +
.../FodyWeavers.xsd | 30 +++
...GYUN.Abp.TaskManagement.Application.csproj | 20 ++
.../BackgroundJobInfoAppService.cs | 161 +++++++++++++
.../TaskManagementApplicationMapperProfile.cs | 11 +
.../TaskManagementApplicationModule.cs | 22 ++
.../TaskManagementApplicationService.cs | 13 ++
.../FodyWeavers.xml | 3 +
.../FodyWeavers.xsd | 30 +++
...UN.Abp.TaskManagement.Domain.Shared.csproj | 27 +++
.../TaskManagement/BackgroundJobInfoConsts.cs | 10 +
.../TaskManagement/BackgroundJobLogConsts.cs | 7 +
.../Localization/Resources/en.json | 6 +
.../Localization/Resources/zh-Hans.json | 6 +
.../Localization/TaskManagementResource.cs | 8 +
.../TaskManagementDomainSharedModule.cs | 34 +++
.../TaskManagementErrorCodes.cs | 9 +
.../FodyWeavers.xml | 3 +
.../FodyWeavers.xsd | 30 +++
.../LINGYUN.Abp.TaskManagement.Domain.csproj | 21 ++
.../Abp/TaskManagement/BackgroundJobInfo.cs | 162 +++++++++++++
.../TaskManagement/BackgroundJobInfoFilter.cs | 67 ++++++
.../Abp/TaskManagement/BackgroundJobLog.cs | 39 ++++
.../TaskManagement/BackgroundJobLogFilter.cs | 35 +++
.../TaskManagement/BackgroundJobManager.cs | 86 +++++++
.../Abp/TaskManagement/BackgroundJobStore.cs | 135 +++++++++++
.../IBackgroundJobInfoRepository.cs | 66 ++++++
.../IBackgroundJobLogRepository.cs | 39 ++++
.../TaskManagementDbProperties.cs | 11 +
.../TaskManagementDomainMapperProfile.cs | 12 +
.../TaskManagementDomainModule.cs | 24 ++
.../FodyWeavers.xml | 3 +
.../FodyWeavers.xsd | 30 +++
....TaskManagement.EntityFrameworkCore.csproj | 19 ++
.../EfCoreBackgroundJobInfoRepository.cs | 124 ++++++++++
.../EfCoreBackgroundJobLogRepository.cs | 63 +++++
.../ITaskManagementDbContext.cs | 9 +
.../TaskManagementDbContext.cs | 20 ++
...agementDbContextModelCreatingExtensions.cs | 81 +++++++
...TaskManagementEntityFrameworkCoreModule.cs | 19 ++
...agementModelBuilderConfigurationOptions.cs | 17 ++
.../FodyWeavers.xml | 3 +
.../FodyWeavers.xsd | 30 +++
.../LINGYUN.Abp.TaskManagement.HttpApi.csproj | 19 ++
.../TaskManagementHttpApiModule.cs | 39 ++++
.../LINGYUN.Abp.TaskManagement.Quartz.csproj | 19 ++
.../Quartz/IQuartzJobExecutorProvider.cs | 10 +
.../Quartz/QuartzJobExecutorProvider.cs | 20 ++
.../Quartz/QuartzJobScheduler.cs | 63 +++++
.../Quartz/QuartzJobSchedulerOptions.cs | 9 +
.../Controllers/HomeController.cs | 12 +
.../Dockerfile | 15 ++
.../TaskManagementMigrationsDbContext.cs | 21 ++
...askManagementMigrationsDbContextFactory.cs | 30 +++
...Service.TaskManagement.HttpApi.Host.csproj | 65 ++++++
.../Program.cs | 44 ++++
.../Properties/launchSettings.json | 21 ++
.../Startup.cs | 30 +++
...skManagementHttpApiHostModule.Configure.cs | 215 ++++++++++++++++++
.../TaskManagementHttpApiHostModule.cs | 114 ++++++++++
.../appsettings.Development.json | 118 ++++++++++
.../appsettings.json | 80 +++++++
.../dapr.sh | 1 +
127 files changed, 4928 insertions(+), 4 deletions(-)
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/FodyWeavers.xml
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/FodyWeavers.xsd
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN.Abp.BackgroundTasks.Abstractions.csproj
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksAbstractionsModule.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobRunnable.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobRunnableExecuter.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobEventContext.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobEventData.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobInfo.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobPriority.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobRunnableContext.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobStatus.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobType.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/FodyWeavers.xml
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/FodyWeavers.xsd
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN.Abp.BackgroundTasks.Quartz.csproj
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/AbpBackgroundTasksQuartzModule.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/IQuartzJobExecutorProvider.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobExecutorProvider.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobListener.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobScheduler.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobSimpleAdapter.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/Quartz/IJobExecutionContextExtensions.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/README.md
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/FodyWeavers.xml
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/FodyWeavers.xsd
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN.Abp.BackgroundTasks.csproj
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksModule.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobAdapter.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobManager.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobEvent.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobEventProvider.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobScheduler.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobStore.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundCleaningJob.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundKeepAliveJob.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundPollingJob.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/DefaultBackgroundWorker.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/InMemoryJobStore.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobEventProvider.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobExecutedEvent.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobLogEvent.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobEventBase.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobRunnableExecuter.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/ConsoleJob.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/EmailingJob.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/README.md
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/FodyWeavers.xml
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/FodyWeavers.xsd
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN.Abp.TaskManagement.Application.Contracts.csproj
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoCreateDto.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoCreateOrUpdateDto.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoDto.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoGetListInput.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoUpdateDto.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobLogDto.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobLogGetListInput.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/IBackgroundJobInfoAppService.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/IBackgroundJobLogAppService.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/Permissions/TaskManagementPermissions.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/TaskManagementApplicationContractsModule.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/FodyWeavers.xml
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/FodyWeavers.xsd
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN.Abp.TaskManagement.Application.csproj
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobInfoAppService.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationMapperProfile.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationModule.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationService.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/FodyWeavers.xml
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/FodyWeavers.xsd
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN.Abp.TaskManagement.Domain.Shared.csproj
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/BackgroundJobInfoConsts.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/BackgroundJobLogConsts.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/en.json
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/zh-Hans.json
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/TaskManagementResource.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/TaskManagementDomainSharedModule.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/TaskManagementErrorCodes.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/FodyWeavers.xml
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/FodyWeavers.xsd
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN.Abp.TaskManagement.Domain.csproj
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobInfo.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobInfoFilter.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLog.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLogFilter.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobManager.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobStore.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/IBackgroundJobInfoRepository.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/IBackgroundJobLogRepository.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/TaskManagementDbProperties.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/TaskManagementDomainMapperProfile.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/TaskManagementDomainModule.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/FodyWeavers.xml
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/FodyWeavers.xsd
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN.Abp.TaskManagement.EntityFrameworkCore.csproj
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/EfCoreBackgroundJobInfoRepository.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/EfCoreBackgroundJobLogRepository.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/ITaskManagementDbContext.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementDbContext.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementDbContextModelCreatingExtensions.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementEntityFrameworkCoreModule.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementModelBuilderConfigurationOptions.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/FodyWeavers.xml
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/FodyWeavers.xsd
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN.Abp.TaskManagement.HttpApi.csproj
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/TaskManagementHttpApiModule.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN.Abp.TaskManagement.Quartz.csproj
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/IQuartzJobExecutorProvider.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/QuartzJobExecutorProvider.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/QuartzJobScheduler.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/QuartzJobSchedulerOptions.cs
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Controllers/HomeController.cs
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Dockerfile
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/EntityFrameworkCore/TaskManagementMigrationsDbContext.cs
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/EntityFrameworkCore/TaskManagementMigrationsDbContextFactory.cs
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/LY.MicroService.TaskManagement.HttpApi.Host.csproj
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Program.cs
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Properties/launchSettings.json
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Startup.cs
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.Configure.cs
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.json
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.json
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/dapr.sh
diff --git a/aspnet-core/.editorconfig b/aspnet-core/.editorconfig
index 2289110b2..9788d77d3 100644
--- a/aspnet-core/.editorconfig
+++ b/aspnet-core/.editorconfig
@@ -1,4 +1,5 @@
-# Rules in this file were initially inferred by Visual Studio IntelliCode from the D:\Projects\MicroService\CRM\Vue\abp-next-admin\aspnet-core codebase based on best match to current usage at 2021-12-27
+# Rules in this file were initially inferred by Visual Studio IntelliCode from the D:\Projects\MicroService\CRM\Vue\abp-next-admin\aspnet-core codebase based on best match to current usage at 2022-01-07
+# There already existed an .editorconfig file in this directory. Copy rules from this .editorconfig.inferred file to the existing .editorconfig file as desired to have them take effect at this location.
# You can modify the rules from these initially generated values to suit your own policies
# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
[*.cs]
@@ -26,8 +27,8 @@ csharp_new_line_before_else = true
csharp_new_line_before_members_in_anonymous_types = true
#require members of object initializers to be on the same line
csharp_new_line_before_members_in_object_initializers = false
-#require braces to be on a new line for anonymous_types, control_blocks, types, lambdas, object_collection_array_initializers, methods, and anonymous_methods (also known as "Allman" style)
-csharp_new_line_before_open_brace = anonymous_types, control_blocks, types, lambdas, object_collection_array_initializers, methods, anonymous_methods
+#require braces to be on a new line for methods, control_blocks, types, lambdas, object_collection_array_initializers, anonymous_methods, and anonymous_types (also known as "Allman" style)
+csharp_new_line_before_open_brace = methods, control_blocks, types, lambdas, object_collection_array_initializers, anonymous_methods, anonymous_types
#Formatting - organize using options
diff --git a/aspnet-core/LINGYUN.MicroService.All.sln b/aspnet-core/LINGYUN.MicroService.All.sln
index 6448be090..cd76d0186 100644
--- a/aspnet-core/LINGYUN.MicroService.All.sln
+++ b/aspnet-core/LINGYUN.MicroService.All.sln
@@ -378,7 +378,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Sms.Tencent", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.BlobStoring.Tencent", "modules\cloud-tencent\LINGYUN.Abp.BlobStoring.Tencent\LINGYUN.Abp.BlobStoring.Tencent.csproj", "{A4B972EC-9F0B-4405-9965-766FABC9B07E}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.OssManagement.Tencent", "modules\oss-management\LINGYUN.Abp.OssManagement.Tencent\LINGYUN.Abp.OssManagement.Tencent.csproj", "{31E60E23-FD98-4D5E-A137-2B3F2968BA09}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OssManagement.Tencent", "modules\oss-management\LINGYUN.Abp.OssManagement.Tencent\LINGYUN.Abp.OssManagement.Tencent.csproj", "{31E60E23-FD98-4D5E-A137-2B3F2968BA09}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/FodyWeavers.xml b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/FodyWeavers.xsd b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN.Abp.BackgroundTasks.Abstractions.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN.Abp.BackgroundTasks.Abstractions.csproj
new file mode 100644
index 000000000..958d8b36d
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN.Abp.BackgroundTasks.Abstractions.csproj
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksAbstractionsModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksAbstractionsModule.cs
new file mode 100644
index 000000000..3e349c78c
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksAbstractionsModule.cs
@@ -0,0 +1,7 @@
+using Volo.Abp.Modularity;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+public class AbpBackgroundTasksAbstractionsModule : AbpModule
+{
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobRunnable.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobRunnable.cs
new file mode 100644
index 000000000..e0471be11
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobRunnable.cs
@@ -0,0 +1,11 @@
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+///
+/// 任务类需要实现此接口
+///
+public interface IJobRunnable
+{
+ Task ExecuteAsync(JobRunnableContext context);
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobRunnableExecuter.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobRunnableExecuter.cs
new file mode 100644
index 000000000..67bceac9c
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobRunnableExecuter.cs
@@ -0,0 +1,12 @@
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+///
+/// 定义任务执行者接口
+/// 可以通过它实现一些限制(例如分布式锁)
+///
+public interface IJobRunnableExecuter
+{
+ Task ExecuteAsync(JobRunnableContext context);
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobEventContext.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobEventContext.cs
new file mode 100644
index 000000000..5fb3042e2
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobEventContext.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+public class JobEventContext
+{
+ public IServiceProvider ServiceProvider { get; }
+ public JobEventData EventData { get; }
+
+ public JobEventContext(
+ IServiceProvider serviceProvider,
+ JobEventData jobEventData)
+ {
+ ServiceProvider = serviceProvider;
+ EventData = jobEventData;
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobEventData.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobEventData.cs
new file mode 100644
index 000000000..fc1852921
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobEventData.cs
@@ -0,0 +1,90 @@
+using System;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+public class JobEventData
+{
+ ///
+ /// 任务类别
+ ///
+ public Type Type { get; }
+ ///
+ /// 任务组别
+ ///
+ public string Group { get; }
+ ///
+ /// 任务名称
+ ///
+ public string Name { get; }
+ ///
+ /// 任务标识
+ ///
+ public Guid Key { get; }
+ ///
+ /// 任务状态
+ ///
+ public JobStatus Status { get; set; }
+ ///
+ /// 执行者租户
+ ///
+ public Guid? TenantId { get; set; }
+ ///
+ /// 错误明细
+ ///
+ public Exception Exception { get; }
+ ///
+ /// 任务描述
+ ///
+ public string Description { get; set; }
+ ///
+ /// 返回参数
+ ///
+ public string Result { get; set; }
+ ///
+ /// 触发次数
+ ///
+ public int Triggered { get; set; }
+ ///
+ /// 最大可执行次数
+ ///
+ public int RepeatCount { get; set; }
+ ///
+ /// 失败重试上限
+ /// 默认:50
+ ///
+ public int TryCount { get; set; }
+ ///
+ /// 最大执行次数
+ /// 默认:0, 无限制
+ ///
+ public int MaxCount { get; set; }
+ ///
+ /// 运行时间
+ ///
+ public DateTime RunTime { get; set; }
+ ///
+ /// 上次运行时间
+ ///
+ public DateTime? LastRunTime { get; set; }
+ ///
+ /// 下次运行时间
+ ///
+ public DateTime? NextRunTime { get; set; }
+ ///
+ /// 连续失败且不会再次执行
+ ///
+ public bool IsAbandoned { get; set; }
+ public JobEventData(
+ Guid key,
+ Type type,
+ string group,
+ string name,
+ Exception exception = null)
+ {
+ Key = key;
+ Type = type;
+ Group = group;
+ Name = name;
+ Exception = exception;
+ }
+}
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
new file mode 100644
index 000000000..ce724e44e
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobInfo.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Collections.Generic;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+public class JobInfo
+{
+ ///
+ /// 任务标识
+ ///
+ public Guid Id { get; set; }
+ ///
+ /// 任务名称
+ ///
+ public string Name { get; set; }
+ ///
+ /// 任务分组
+ ///
+ public string Group { get; set; }
+ ///
+ /// 任务类型
+ ///
+ public string Type { get; set; }
+ ///
+ /// 返回参数
+ ///
+ public string Result { get; set; }
+ ///
+ /// 任务参数
+ ///
+ public IDictionary Args { get; set; }
+ ///
+ /// 任务状态
+ ///
+ public JobStatus Status { get; set; } = JobStatus.None;
+ ///
+ /// 描述
+ ///
+ public string Description { get; set; }
+ ///
+ /// 创建时间
+ ///
+ public DateTime CreationTime { get; set; }
+ ///
+ /// 开始时间
+ ///
+ public DateTime BeginTime { get; set; }
+ ///
+ /// 结束时间
+ ///
+ public DateTime? EndTime { get; set; }
+ ///
+ /// 上次运行时间
+ ///
+ public DateTime? LastRunTime { get; set; }
+ ///
+ /// 下一次执行时间
+ ///
+ public DateTime? NextRunTime { get; set; }
+ ///
+ /// 任务类别
+ ///
+ public JobType JobType { get; set; } = JobType.Once;
+ ///
+ /// Cron表达式,如果是持续任务需要指定
+ ///
+ public string Cron { get; set; }
+ ///
+ /// 触发次数
+ ///
+ public int TriggerCount { get; set; }
+ ///
+ /// 失败重试次数
+ ///
+ public int TryCount { get; set; }
+ ///
+ /// 失败重试上限
+ /// 默认:50
+ ///
+ public int MaxTryCount { get; set; } = 50;
+ ///
+ /// 最大执行次数
+ /// 默认:0, 无限制
+ ///
+ public int MaxCount { get; set; }
+ ///
+ /// 连续失败且不会再次执行
+ ///
+ public bool IsAbandoned { get; set; }
+ ///
+ /// 间隔时间,单位秒,与Cron表达式冲突
+ /// 默认: 300
+ ///
+ public int Interval { get; set; } = 300;
+ ///
+ /// 任务优先级
+ ///
+ public JobPriority Priority { get; set; } = JobPriority.Normal;
+ ///
+ /// 任务独占超时时长(秒)
+ /// 0或更小不生效
+ ///
+ public int LockTimeOut { get; set; }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobPriority.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobPriority.cs
new file mode 100644
index 000000000..dac91b3fa
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobPriority.cs
@@ -0,0 +1,15 @@
+namespace LINGYUN.Abp.BackgroundTasks;
+///
+/// 任务优先级
+///
+///
+/// 与框架保持一致
+///
+public enum JobPriority
+{
+ Low = 5,
+ BelowNormal = 10,
+ Normal = 0xF,
+ AboveNormal = 20,
+ High = 25
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobRunnableContext.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobRunnableContext.cs
new file mode 100644
index 000000000..75af712ad
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobRunnableContext.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+public class JobRunnableContext
+{
+ public Type JobType { get; }
+ public IServiceProvider ServiceProvider { get; }
+ public IReadOnlyDictionary JobData { get; }
+ public JobRunnableContext(
+ Type jobType,
+ IServiceProvider serviceProvider,
+ IReadOnlyDictionary jobData)
+ {
+ JobType = jobType;
+ ServiceProvider = serviceProvider;
+ JobData = jobData;
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobStatus.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobStatus.cs
new file mode 100644
index 000000000..c46492592
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobStatus.cs
@@ -0,0 +1,25 @@
+namespace LINGYUN.Abp.BackgroundTasks;
+
+public enum JobStatus
+{
+ ///
+ /// 未知
+ ///
+ None = -1,
+ ///
+ /// 已完成
+ ///
+ Completed = 0,
+ ///
+ /// 运行中
+ ///
+ Running = 10,
+ ///
+ /// 已暂停
+ ///
+ Paused = 20,
+ ///
+ /// 已停止
+ ///
+ Stopped = 30
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobType.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobType.cs
new file mode 100644
index 000000000..2fb57a07f
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobType.cs
@@ -0,0 +1,19 @@
+namespace LINGYUN.Abp.BackgroundTasks;
+///
+/// 任务类别
+///
+public enum JobType
+{
+ ///
+ /// 一次性
+ ///
+ Once,
+ ///
+ /// 周期性
+ ///
+ Period,
+ ///
+ /// 持续性
+ ///
+ Persistent
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/FodyWeavers.xml b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/FodyWeavers.xsd b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN.Abp.BackgroundTasks.Quartz.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN.Abp.BackgroundTasks.Quartz.csproj
new file mode 100644
index 000000000..386fea967
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN.Abp.BackgroundTasks.Quartz.csproj
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
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
new file mode 100644
index 000000000..983823e05
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/AbpBackgroundTasksQuartzModule.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.DependencyInjection;
+using Quartz;
+using Volo.Abp;
+using Volo.Abp.Modularity;
+using Volo.Abp.Quartz;
+
+namespace LINGYUN.Abp.BackgroundTasks.Quartz;
+
+[DependsOn(typeof(AbpBackgroundTasksModule))]
+[DependsOn(typeof(AbpQuartzModule))]
+public class AbpBackgroundTasksQuartzModule : AbpModule
+{
+ public override void OnApplicationInitialization(ApplicationInitializationContext context)
+ {
+ var _scheduler = context.ServiceProvider.GetRequiredService();
+
+ _scheduler.ListenerManager.AddJobListener(context.ServiceProvider.GetRequiredService());
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/IQuartzJobExecutorProvider.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/IQuartzJobExecutorProvider.cs
new file mode 100644
index 000000000..6fd447334
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/IQuartzJobExecutorProvider.cs
@@ -0,0 +1,12 @@
+using Quartz;
+
+namespace LINGYUN.Abp.BackgroundTasks.Quartz;
+
+public interface IQuartzJobExecutorProvider
+{
+#nullable enable
+ IJobDetail? CreateJob(JobInfo job);
+
+ ITrigger CreateTrigger(JobInfo job);
+#nullable disable
+}
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
new file mode 100644
index 000000000..ec3ab3501
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobExecutorProvider.cs
@@ -0,0 +1,102 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
+using Quartz;
+using System;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Timing;
+
+namespace LINGYUN.Abp.BackgroundTasks.Quartz;
+
+public class QuartzJobExecutorProvider : IQuartzJobExecutorProvider, ISingletonDependency
+{
+ public ILogger Logger { protected get; set; }
+
+ protected IClock Clock { get; }
+ protected AbpBackgroundTasksOptions Options { get; }
+
+ public QuartzJobExecutorProvider(
+ IClock clock,
+ IOptions options)
+ {
+ Clock = clock;
+ Options = options.Value;
+
+ Logger = NullLogger.Instance;
+ }
+
+ public IJobDetail CreateJob(JobInfo job)
+ {
+ var jobType = Type.GetType(job.Type);
+ if (jobType == null)
+ {
+ Logger.LogWarning($"The task: {job.Group} - {job.Name}: {job.Type} is not registered and cannot create an instance of the performer type.");
+ return null;
+ }
+
+ var adapterType = typeof(QuartzJobSimpleAdapter<>);
+
+ if (!typeof(IJob).IsAssignableFrom(jobType))
+ {
+ jobType = adapterType.MakeGenericType(jobType);
+ }
+
+ var jobBuilder = JobBuilder.Create(jobType)
+ .WithIdentity(job.Name, job.Group)
+ .WithDescription(job.Description);
+
+ jobBuilder.UsingJobData(nameof(JobInfo.Id), job.Id);
+ jobBuilder.UsingJobData(nameof(JobInfo.LockTimeOut), job.LockTimeOut);
+ jobBuilder.UsingJobData(new JobDataMap(job.Args));
+
+ return jobBuilder.Build();
+ }
+
+ public ITrigger CreateTrigger(JobInfo job)
+ {
+ var triggerBuilder = TriggerBuilder.Create();
+
+ switch (job.JobType)
+ {
+ case JobType.Period:
+ if (!CronExpression.IsValidExpression(job.Cron))
+ {
+ Logger.LogWarning($"The task: {job.Group} - {job.Name} periodic task Cron expression was invalid and the task trigger could not be created.");
+ return null;
+ }
+ triggerBuilder
+ .WithIdentity(job.Name, job.Group)
+ .WithDescription(job.Description)
+ .EndAt(job.EndTime)
+ .ForJob(job.Name, job.Group)
+ .WithPriority((int)job.Priority)
+ .WithCronSchedule(job.Cron);
+ if (job.BeginTime > Clock.Now)
+ {
+ triggerBuilder = triggerBuilder.StartAt(job.BeginTime);
+ }
+ break;
+ case JobType.Once:
+ case JobType.Persistent:
+ default:
+ // Quartz 需要减一位
+ var maxCount = job.MaxCount <= 0 ? -1 : job.MaxCount - 1;
+ if (job.JobType == JobType.Once)
+ {
+ maxCount = 0;
+ }
+ triggerBuilder
+ .WithIdentity(job.Name, job.Group)
+ .WithDescription(job.Description)
+ .EndAt(job.EndTime)
+ .ForJob(job.Name, job.Group)
+ .WithPriority((int)job.Priority)
+ .WithSimpleSchedule(x =>
+ x.WithIntervalInSeconds(job.Interval)
+ .WithRepeatCount(maxCount));
+ break;
+ }
+
+ return triggerBuilder.Build();
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobListener.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobListener.cs
new file mode 100644
index 000000000..7408ffcf2
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobListener.cs
@@ -0,0 +1,144 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Quartz;
+using Quartz.Listener;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.MultiTenancy;
+using Volo.Abp.Uow;
+
+namespace LINGYUN.Abp.BackgroundTasks.Quartz;
+
+public class QuartzJobListener : JobListenerSupport, ISingletonDependency
+{
+ public ILogger Logger { protected get; set; }
+
+ public override string Name => "QuartzJobListener";
+
+ protected IJobEventProvider EventProvider { get; }
+ protected IServiceProvider ServiceProvider { get; }
+
+ public QuartzJobListener(
+ IServiceProvider serviceProvider,
+ IJobEventProvider eventProvider)
+ {
+ ServiceProvider = serviceProvider;
+ EventProvider = eventProvider;
+
+ Logger = NullLogger.Instance;
+ }
+
+ public override Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default)
+ {
+ var jobType = context.JobDetail.JobType;
+ if (jobType.IsGenericType)
+ {
+ jobType = jobType.GetGenericTypeDefinition();
+ }
+ Logger.LogInformation($"The task {jobType.Name} could not be performed...");
+
+ return Task.FromResult(-1);
+ }
+
+ public override async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default)
+ {
+ var jobId = context.GetString(nameof(JobInfo.Id));
+ if (Guid.TryParse(jobId, out var jobUUId))
+ {
+ try
+ {
+ using var scope = ServiceProvider.CreateScope();
+ var jobEventData = new JobEventData(
+ jobUUId,
+ context.JobDetail.JobType,
+ context.JobDetail.Key.Group,
+ context.JobDetail.Key.Name)
+ {
+ Result = context.Result?.ToString()
+ };
+
+ var jobEventList = EventProvider.GetAll();
+ var eventContext = new JobEventContext(
+ scope.ServiceProvider,
+ jobEventData);
+
+ var index = 0;
+ var taskList = new Task[jobEventList.Count];
+ foreach (var jobEvent in jobEventList)
+ {
+ taskList[index] = jobEvent.OnJobBeforeExecuted(eventContext);
+ index++;
+ }
+
+ await Task.WhenAll(taskList);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError($"The event before the task execution is abnormal:{ex}");
+ }
+ }
+ }
+
+ [UnitOfWork]
+ public override async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ using var scope = ServiceProvider.CreateScope();
+ var jobId = context.GetString(nameof(JobInfo.Id));
+ if (Guid.TryParse(jobId, out var jobUUId))
+ {
+ var jobEventData = new JobEventData(
+ jobUUId,
+ context.JobDetail.JobType,
+ context.JobDetail.Key.Group,
+ context.JobDetail.Key.Name,
+ jobException)
+ {
+ Status = JobStatus.Running
+ };
+
+ if (context.Trigger is ISimpleTrigger simpleTrigger)
+ {
+ jobEventData.Triggered = simpleTrigger.TimesTriggered;
+ jobEventData.RepeatCount = simpleTrigger.RepeatCount;
+ }
+ jobEventData.Description = context.JobDetail.Description;
+ jobEventData.RunTime = context.FireTimeUtc.LocalDateTime;
+ jobEventData.LastRunTime = context.PreviousFireTimeUtc?.LocalDateTime;
+ jobEventData.NextRunTime = context.NextFireTimeUtc?.LocalDateTime;
+ if (context.Result != null)
+ {
+ jobEventData.Result = context.Result.ToString();
+ }
+ var tenantIdString = context.GetString(nameof(IMultiTenant.TenantId));
+ if (Guid.TryParse(tenantIdString, out var tenantId))
+ {
+ jobEventData.TenantId = tenantId;
+ }
+
+ var jobEventList = EventProvider.GetAll();
+ var eventContext = new JobEventContext(
+ scope.ServiceProvider,
+ jobEventData);
+
+ var index = 0;
+ var taskList = new Task[jobEventList.Count];
+ foreach (var jobEvent in jobEventList)
+ {
+ taskList[index] = jobEvent.OnJobAfterExecuted(eventContext);
+ index++;
+ }
+
+ await Task.WhenAll(taskList);
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError($"The event is abnormal after the task is executed:{ex}");
+ }
+ }
+}
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
new file mode 100644
index 000000000..6b87ff4fd
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobScheduler.cs
@@ -0,0 +1,164 @@
+using Quartz;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.BackgroundTasks.Quartz;
+
+[Dependency(ReplaceServices = true)]
+public class QuartzJobScheduler : IJobScheduler, ISingletonDependency
+{
+ protected IJobStore JobStore { get; }
+ protected IScheduler Scheduler { get; }
+ protected IQuartzJobExecutorProvider QuartzJobExecutor { get; }
+
+ public QuartzJobScheduler(
+ IJobStore jobStore,
+ IScheduler scheduler,
+ IQuartzJobExecutorProvider quartzJobExecutor)
+ {
+ JobStore = jobStore;
+ Scheduler = scheduler;
+ QuartzJobExecutor = quartzJobExecutor;
+ }
+
+ public virtual async Task ExistsAsync(JobInfo job)
+ {
+ var jobKey = new JobKey(job.Name, job.Group);
+ return await Scheduler.CheckExists(jobKey);
+ }
+
+ public virtual async Task PauseAsync(JobInfo job)
+ {
+ var jobKey = new JobKey(job.Name, job.Group);
+ if (await Scheduler.CheckExists(jobKey))
+ {
+ var triggers = await Scheduler.GetTriggersOfJob(jobKey);
+ foreach (var trigger in triggers)
+ {
+ await Scheduler.PauseTrigger(trigger.Key);
+ }
+ }
+ }
+
+ public virtual async Task QueueAsync(JobInfo job)
+ {
+ var jobKey = new JobKey(job.Name, job.Group);
+ if (await Scheduler.CheckExists(jobKey))
+ {
+ return false;
+ }
+
+ var jobDetail = QuartzJobExecutor.CreateJob(job);
+ if (jobDetail == null)
+ {
+ return false;
+ }
+
+ var jobTrigger = QuartzJobExecutor.CreateTrigger(job);
+ if (jobTrigger == null)
+ {
+ return false;
+ }
+
+ await Scheduler.ScheduleJob(jobDetail, jobTrigger);
+
+ return await Scheduler.CheckExists(jobTrigger.Key);
+ }
+
+ public virtual async Task QueuesAsync(IEnumerable jobs)
+ {
+ var jobDictionary = new Dictionary>();
+ foreach (var job in jobs)
+ {
+ var jobDetail = QuartzJobExecutor.CreateJob(job);
+ if (jobDetail == null)
+ {
+ continue;
+ }
+
+ var jobTrigger = QuartzJobExecutor.CreateTrigger(job);
+ if (jobTrigger == null)
+ {
+ continue;
+ }
+
+ jobDictionary.Add(jobDetail, new ITrigger[] { jobTrigger });
+ }
+
+ await Scheduler.ScheduleJobs(jobDictionary, false);
+ }
+
+ public virtual async Task RemoveAsync(JobInfo job)
+ {
+ var jobKey = new JobKey(job.Name, job.Group);
+ if (!await Scheduler.CheckExists(jobKey))
+ {
+ return false;
+ }
+
+ var triggers = await Scheduler.GetTriggersOfJob(jobKey);
+ foreach (var trigger in triggers)
+ {
+ await Scheduler.PauseTrigger(trigger.Key);
+ }
+ await Scheduler.DeleteJob(jobKey);
+
+ return !await Scheduler.CheckExists(jobKey);
+ }
+
+ public virtual async Task ResumeAsync(JobInfo job)
+ {
+ var jobKey = new JobKey(job.Name, job.Group);
+ if (await Scheduler.CheckExists(jobKey))
+ {
+ var triggers = await Scheduler.GetTriggersOfJob(jobKey);
+ foreach (var trigger in triggers)
+ {
+ await Scheduler.ResumeTrigger(trigger.Key);
+ }
+ }
+ }
+
+ public virtual async Task ShutdownAsync()
+ {
+ await StopAsync();
+
+ await Scheduler.Shutdown(true);
+
+ return Scheduler.IsShutdown;
+ }
+
+ public virtual async Task StartAsync()
+ {
+ if (Scheduler.InStandbyMode)
+ {
+ await Scheduler.Start();
+ }
+ return Scheduler.InStandbyMode;
+ }
+
+ public virtual async Task StopAsync()
+ {
+ if (!Scheduler.InStandbyMode)
+ {
+ //等待任务运行完成
+ await Scheduler.Standby();
+ }
+ return !Scheduler.InStandbyMode;
+ }
+
+ public virtual async Task TriggerAsync(JobInfo job)
+ {
+ var jobKey = new JobKey(job.Name, job.Group);
+ if (await Scheduler.CheckExists(jobKey))
+ {
+ await Scheduler.TriggerJob(jobKey);
+ }
+ else
+ {
+ throw new AbpException("This task could not be found in task scheduler, please confirm that it is enabled?");
+ }
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobSimpleAdapter.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobSimpleAdapter.cs
new file mode 100644
index 000000000..55b65a3af
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobSimpleAdapter.cs
@@ -0,0 +1,33 @@
+using Microsoft.Extensions.DependencyInjection;
+using Quartz;
+using System;
+using System.Collections.Immutable;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.BackgroundTasks.Quartz;
+
+public class QuartzJobSimpleAdapter : IJob
+ where TJobRunnable : IJobRunnable
+{
+ protected IServiceProvider ServiceProvider { get; }
+
+ public QuartzJobSimpleAdapter(
+ IServiceProvider serviceProvider)
+ {
+ ServiceProvider = serviceProvider;
+ }
+
+ public async virtual Task Execute(IJobExecutionContext context)
+ {
+ // 任务已经在一个作用域中
+ // using var scope = ServiceProvider.CreateScope();
+ var jobExecuter = ServiceProvider.GetRequiredService();
+
+ var jobContext = new JobRunnableContext(
+ typeof(TJobRunnable),
+ ServiceProvider,
+ context.MergedJobDataMap.ToImmutableDictionary());
+
+ await jobExecuter.ExecuteAsync(jobContext);
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/Quartz/IJobExecutionContextExtensions.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/Quartz/IJobExecutionContextExtensions.cs
new file mode 100644
index 000000000..3d46e4614
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/Quartz/IJobExecutionContextExtensions.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Quartz;
+
+public static class IJobExecutionContextExtensions
+{
+ public static TValue GetData(this IJobExecutionContext context, string key)
+ {
+ var value = context.MergedJobDataMap.GetString(key);
+
+ return (TValue)Convert.ChangeType(value, typeof(TValue));
+ }
+
+ public static string GetString(this IJobExecutionContext context, string key)
+ {
+ var value = context.MergedJobDataMap.Get(key);
+
+ return value != null ? value.ToString() : "";
+ }
+
+ public static int GetInt(this IJobExecutionContext context, string key)
+ {
+ var value = context.MergedJobDataMap.GetInt(key);
+
+ return value;
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/README.md b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/README.md
new file mode 100644
index 000000000..b1dd81e5b
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/README.md
@@ -0,0 +1,16 @@
+# LINGYUN.Abp.BackgroundTasks.Quartz
+
+后台任务(队列)模块的Quartz实现, 使用任务适配器来做到任务的幂等性控制.
+并添加一个监听器用于通知管理者任务状态
+
+## 配置使用
+
+模块按需引用,具体配置参考Volo.Abp.Quartz模块
+
+```csharp
+[DependsOn(typeof(AbpBackgroundTasksQuartzModule))]
+public class YouProjectModule : AbpModule
+{
+ // other
+}
+```
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/FodyWeavers.xml b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/FodyWeavers.xsd b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN.Abp.BackgroundTasks.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN.Abp.BackgroundTasks.csproj
new file mode 100644
index 000000000..96b629b02
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN.Abp.BackgroundTasks.csproj
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksModule.cs
new file mode 100644
index 000000000..205ccd0e9
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksModule.cs
@@ -0,0 +1,49 @@
+using LINGYUN.Abp.BackgroundTasks.Internal;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using Volo.Abp.Auditing;
+using Volo.Abp.BackgroundJobs;
+using Volo.Abp.DistributedLocking;
+using Volo.Abp.Guids;
+using Volo.Abp.Modularity;
+using Volo.Abp.Reflection;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+[DependsOn(typeof(AbpAuditingModule))]
+[DependsOn(typeof(AbpDistributedLockingModule))]
+[DependsOn(typeof(AbpBackgroundTasksAbstractionsModule))]
+[DependsOn(typeof(AbpBackgroundJobsAbstractionsModule))]
+[DependsOn(typeof(AbpGuidsModule))]
+public class AbpBackgroundTasksModule : AbpModule
+{
+ public override void PreConfigureServices(ServiceConfigurationContext context)
+ {
+ AutoAddJobMonitors(context.Services);
+ }
+
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ context.Services.AddTransient(typeof(BackgroundJobAdapter<>));
+ context.Services.AddHostedService();
+ }
+
+ private static void AutoAddJobMonitors(IServiceCollection services)
+ {
+ var jobMonitors = new List();
+
+ services.OnRegistred(context =>
+ {
+ if (ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(JobEventBase<>)))
+ {
+ jobMonitors.Add(context.ImplementationType);
+ }
+ });
+
+ services.Configure(options =>
+ {
+ options.JobMonitors.AddIfNotContains(jobMonitors);
+ });
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs
new file mode 100644
index 000000000..69457817b
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs
@@ -0,0 +1,69 @@
+using System;
+using Volo.Abp.Collections;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+public class AbpBackgroundTasksOptions
+{
+ ///
+ /// 任务监听类型列表
+ ///
+ ///
+ /// 用户可以实现事件监听实现自定义逻辑
+ ///
+ public ITypeList JobMonitors { get; }
+ ///
+ /// 任务过期时间
+ /// 默认: 15 days
+ ///
+ ///
+ /// 任务过期时间,超出时间段清理
+ ///
+ public TimeSpan JobExpiratime { get; set; }
+ ///
+ /// 每次清理任务批次大小
+ /// 默认: 1000
+ ///
+ public int MaxJobCleanCount { get; set; }
+ ///
+ /// 清理过期任务批次Cron表达式
+ /// 默认: 600秒(0 0/10 * * * ? * )
+ ///
+ ///
+ /// Cron表达式
+ ///
+ public string JobCleanCronExpression { get; set; }
+ ///
+ /// 每次轮询任务批次大小
+ /// 默认: 1000
+ ///
+ public int MaxJobFetchCount { get; set; }
+ ///
+ /// 轮询任务批次Cron表达式
+ /// 默认: 30秒(0/30 * * * * ? )
+ ///
+ ///
+ /// Cron表达式
+ ///
+ public string JobFetchCronExpression { get; set; }
+ ///
+ /// 轮询任务批次时锁定任务超时时长(秒)
+ /// 默认:120
+ ///
+ ///
+ /// 轮询任务也属于一个后台任务, 需要对每一次轮询加锁,防止重复任务入库
+ ///
+ public int JobFetchLockTimeOut { get; set; }
+ public AbpBackgroundTasksOptions()
+ {
+ MaxJobFetchCount = 1000;
+ JobFetchLockTimeOut = 120;
+ JobFetchCronExpression = "0/30 * * * * ? ";
+
+ MaxJobCleanCount = 1000;
+ JobExpiratime = TimeSpan.FromDays(15d);
+ JobCleanCronExpression = "0 0/10 * * * ? *";
+
+ JobMonitors = new TypeList();
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobAdapter.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobAdapter.cs
new file mode 100644
index 000000000..10e2dfd3a
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobAdapter.cs
@@ -0,0 +1,39 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp.BackgroundJobs;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+public class BackgroundJobAdapter : IJobRunnable
+{
+ public ILogger> Logger { protected get; set; }
+
+ protected AbpBackgroundJobOptions Options { get; }
+ protected IServiceScopeFactory ServiceScopeFactory { get; }
+ protected IBackgroundJobExecuter JobExecuter { get; }
+
+ public BackgroundJobAdapter(
+ IOptions options,
+ IBackgroundJobExecuter jobExecuter,
+ IServiceScopeFactory serviceScopeFactory)
+ {
+ JobExecuter = jobExecuter;
+ ServiceScopeFactory = serviceScopeFactory;
+ Options = options.Value;
+
+ Logger = NullLogger>.Instance;
+ }
+
+ public virtual async Task ExecuteAsync(JobRunnableContext context)
+ {
+ using var scope = ServiceScopeFactory.CreateScope();
+ var args = context.JobData.GetOrDefault(nameof(TArgs));
+ var jobType = Options.GetJob(typeof(TArgs)).JobType;
+ var jobContext = new JobExecutionContext(scope.ServiceProvider, jobType, args);
+ await JobExecuter.ExecuteAsync(jobContext);
+ }
+}
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
new file mode 100644
index 000000000..9df770d40
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobManager.cs
@@ -0,0 +1,82 @@
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp.BackgroundJobs;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Guids;
+using Volo.Abp.Timing;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+[Dependency(ReplaceServices = true)]
+public class BackgroundJobManager : IBackgroundJobManager, ITransientDependency
+{
+ protected IClock Clock { get; }
+ protected IJobStore JobStore { get; }
+ protected IGuidGenerator GuidGenerator { get; }
+ protected AbpBackgroundJobOptions Options { get; }
+ public BackgroundJobManager(
+ IClock clock,
+ IJobStore jobStore,
+ IGuidGenerator guidGenerator,
+ IOptions options)
+ {
+ Clock = clock;
+ JobStore = jobStore;
+ GuidGenerator = guidGenerator;
+ Options = options.Value;
+ }
+
+ public virtual async Task EnqueueAsync(
+ TArgs args,
+ BackgroundJobPriority priority = BackgroundJobPriority.Normal,
+ TimeSpan? delay = null)
+ {
+ var jobConfiguration = Options.GetJob();
+ var interval = 60;
+ if (delay.HasValue)
+ {
+ interval = delay.Value.Seconds;
+ }
+ var jobId = GuidGenerator.Create();
+ var jobArgs = new Dictionary
+ {
+ { nameof(TArgs), args },
+ { "ArgsType", jobConfiguration.ArgsType.AssemblyQualifiedName },
+ { "JobType", typeof(BackgroundJobAdapter).AssemblyQualifiedName },
+ };
+ var jobInfo = new JobInfo
+ {
+ Id = jobId,
+ Name = jobConfiguration.JobName,
+ Group = "BackgroundJobs",
+ Priority = ConverForm(priority),
+ BeginTime = DateTime.Now,
+ Args = jobArgs,
+ Description = "From the framework background jobs",
+ JobType = JobType.Once,
+ Interval = interval,
+ CreationTime = Clock.Now,
+ Status = JobStatus.Running,
+ Type = typeof(BackgroundJobAdapter).AssemblyQualifiedName,
+ };
+
+ // 作为一次性任务持久化
+ await JobStore.StoreAsync(jobInfo);
+
+ return jobId.ToString();
+ }
+
+ private JobPriority ConverForm(BackgroundJobPriority priority)
+ {
+ return priority switch
+ {
+ BackgroundJobPriority.Low => JobPriority.Low,
+ BackgroundJobPriority.High => JobPriority.High,
+ BackgroundJobPriority.BelowNormal => JobPriority.BelowNormal,
+ BackgroundJobPriority.AboveNormal => JobPriority.AboveNormal,
+ _ => JobPriority.Normal,
+ };
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobEvent.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobEvent.cs
new file mode 100644
index 000000000..3775644b4
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobEvent.cs
@@ -0,0 +1,22 @@
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+///
+/// 挂载任务事件接口
+///
+public interface IJobEvent
+{
+ ///
+ /// 任务启动前事件
+ ///
+ ///
+ ///
+ Task OnJobBeforeExecuted(JobEventContext context);
+ ///
+ /// 任务完成后事件
+ ///
+ ///
+ ///
+ Task OnJobAfterExecuted(JobEventContext context);
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobEventProvider.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobEventProvider.cs
new file mode 100644
index 000000000..9b3dc6f09
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobEventProvider.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+///
+/// 任务事件提供者
+///
+public interface IJobEventProvider
+{
+ ///
+ /// 返回所有任务事件注册接口
+ ///
+ ///
+ IReadOnlyCollection GetAll();
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobScheduler.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobScheduler.cs
new file mode 100644
index 000000000..4ec76be9a
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobScheduler.cs
@@ -0,0 +1,72 @@
+using System.Threading.Tasks;
+using System.Collections.Generic;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+///
+/// 作业调度接口
+///
+public interface IJobScheduler
+{
+ ///
+ /// 任务入队
+ ///
+ ///
+ ///
+ Task QueueAsync(JobInfo job);
+ ///
+ /// 任务入队
+ ///
+ ///
+ ///
+ Task QueuesAsync(IEnumerable jobs);
+ ///
+ /// 任务是否存在
+ ///
+ ///
+ ///
+ ///
+ Task ExistsAsync(JobInfo job);
+ ///
+ /// 触发任务
+ ///
+ ///
+ ///
+ ///
+ Task TriggerAsync(JobInfo job);
+ ///
+ /// 暂停任务
+ ///
+ ///
+ ///
+ ///
+ Task PauseAsync(JobInfo job);
+ ///
+ /// 恢复暂停的任务
+ ///
+ ///
+ ///
+ ///
+ Task ResumeAsync(JobInfo job);
+ ///
+ /// 移除任务
+ ///
+ ///
+ ///
+ ///
+ Task RemoveAsync(JobInfo job);
+ ///
+ /// 启动任务协调器
+ ///
+ ///
+ Task StartAsync();
+ ///
+ /// 停止任务协调器
+ ///
+ ///
+ Task StopAsync();
+ ///
+ /// 释放任务协调器
+ ///
+ ///
+ Task ShutdownAsync();
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobStore.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobStore.cs
new file mode 100644
index 000000000..9dd69ca0c
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobStore.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+public interface IJobStore
+{
+ Task> GetWaitingListAsync(
+ int maxResultCount,
+ CancellationToken cancellationToken = default);
+
+ Task> GetAllPeriodTasksAsync(
+ CancellationToken cancellationToken = default);
+
+ Task FindAsync(Guid jobId);
+
+ Task StoreAsync(JobInfo jobInfo);
+
+ Task StoreLogAsync(JobEventData eventData);
+
+ Task CleanupAsync(
+ int maxResultCount,
+ TimeSpan jobExpiratime,
+ CancellationToken cancellationToken = default);
+}
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
new file mode 100644
index 000000000..ee767808d
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundCleaningJob.cs
@@ -0,0 +1,18 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.BackgroundTasks.Internal;
+
+internal class BackgroundCleaningJob : IJobRunnable
+{
+ public virtual async Task ExecuteAsync(JobRunnableContext context)
+ {
+ var options = context.ServiceProvider.GetRequiredService>().Value;
+ var store = context.ServiceProvider.GetRequiredService();
+
+ 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
new file mode 100644
index 000000000..1f47228c2
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundKeepAliveJob.cs
@@ -0,0 +1,26 @@
+using Microsoft.Extensions.DependencyInjection;
+using System.Linq;
+using System.Threading.Tasks;
+using Volo.Abp.Auditing;
+
+namespace LINGYUN.Abp.BackgroundTasks.Internal;
+
+[DisableAuditing]
+internal class BackgroundKeepAliveJob : IJobRunnable
+{
+ public virtual async Task ExecuteAsync(JobRunnableContext context)
+ {
+ var store = context.ServiceProvider.GetRequiredService();
+
+ var periodJobs = await store.GetAllPeriodTasksAsync();
+
+ if (!periodJobs.Any())
+ {
+ return;
+ }
+
+ var jobScheduler = context.ServiceProvider.GetRequiredService();
+
+ await jobScheduler.QueuesAsync(periodJobs);
+ }
+}
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
new file mode 100644
index 000000000..699c3bc72
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/BackgroundPollingJob.cs
@@ -0,0 +1,31 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using System.Linq;
+using System.Threading.Tasks;
+using Volo.Abp.Auditing;
+
+namespace LINGYUN.Abp.BackgroundTasks.Internal;
+
+[DisableAuditing]
+internal class BackgroundPollingJob : IJobRunnable
+{
+ public virtual async Task ExecuteAsync(JobRunnableContext context)
+ {
+ var options = context.ServiceProvider.GetRequiredService>().Value;
+ var store = context.ServiceProvider.GetRequiredService();
+
+ var waitingJobs = await store.GetWaitingListAsync(options.MaxJobFetchCount);
+
+ if (!waitingJobs.Any())
+ {
+ return;
+ }
+
+ 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
new file mode 100644
index 000000000..e86ae7879
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/DefaultBackgroundWorker.cs
@@ -0,0 +1,108 @@
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.BackgroundTasks.Internal;
+
+internal class DefaultBackgroundWorker : BackgroundService
+{
+ private readonly IJobStore _jobStore;
+ private readonly IJobScheduler _jobScheduler;
+ private readonly AbpBackgroundTasksOptions _options;
+
+ public DefaultBackgroundWorker(
+ IJobStore jobStore,
+ IJobScheduler jobScheduler,
+ IOptions options)
+ {
+ _jobStore = jobStore;
+ _jobScheduler = jobScheduler;
+ _options = options.Value;
+ }
+
+ protected async override Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ await QueuePollingJob();
+ await QueueKeepAliveJob();
+ await QueueCleaningJob();
+ }
+
+ private async Task QueueKeepAliveJob()
+ {
+ var keepAliveJob = BuildKeepAliveJobInfo();
+ await _jobScheduler.QueueAsync(keepAliveJob);
+ }
+
+ private async Task QueuePollingJob()
+ {
+ var pollingJob = BuildPollingJobInfo();
+ await _jobScheduler.QueueAsync(pollingJob);
+ }
+
+ private async Task QueueCleaningJob()
+ {
+ var cleaningJob = BuildCleaningJobInfo();
+ await _jobScheduler.QueueAsync(cleaningJob);
+ }
+
+ private JobInfo BuildKeepAliveJobInfo()
+ {
+ return new JobInfo
+ {
+ Id = Guid.Parse("8F50C5D9-5691-4B99-A52B-CABD91D93C89"),
+ Name = nameof(BackgroundKeepAliveJob),
+ Group = "Default",
+ Description = "Add periodic tasks",
+ Args = new Dictionary(),
+ Status = JobStatus.Running,
+ BeginTime = DateTime.Now,
+ CreationTime = DateTime.Now,
+ JobType = JobType.Once,
+ Priority = JobPriority.High,
+ MaxCount = 1,
+ Type = typeof(BackgroundKeepAliveJob).AssemblyQualifiedName,
+ };
+ }
+
+ private JobInfo BuildPollingJobInfo()
+ {
+ return new JobInfo
+ {
+ Id = Guid.Parse("C51152E9-F0B8-4252-8352-283BE46083CC"),
+ Name = nameof(BackgroundPollingJob),
+ Group = "Default",
+ Description = "Polling tasks to be executed",
+ Args = new Dictionary(),
+ Status = JobStatus.Running,
+ BeginTime = DateTime.Now,
+ CreationTime = DateTime.Now,
+ Cron = _options.JobFetchCronExpression,
+ JobType = JobType.Period,
+ Priority = JobPriority.High,
+ LockTimeOut = _options.JobFetchLockTimeOut,
+ Type = typeof(BackgroundPollingJob).AssemblyQualifiedName,
+ };
+ }
+
+ private JobInfo BuildCleaningJobInfo()
+ {
+ return new JobInfo
+ {
+ Id = Guid.Parse("AAAF8783-FA06-4CF9-BDCA-11140FB2478F"),
+ Name = nameof(BackgroundCleaningJob),
+ Group = "Default",
+ Description = "Cleaning tasks to be executed",
+ Args = new Dictionary(),
+ Status = JobStatus.Running,
+ BeginTime = DateTime.Now,
+ CreationTime = DateTime.Now,
+ Cron = _options.JobCleanCronExpression,
+ JobType = JobType.Period,
+ Priority = JobPriority.High,
+ Type = typeof(BackgroundCleaningJob).AssemblyQualifiedName,
+ };
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/InMemoryJobStore.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/InMemoryJobStore.cs
new file mode 100644
index 000000000..b6c654ebc
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/InMemoryJobStore.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.BackgroundTasks.Internal;
+
+[Dependency(TryRegister = true)]
+internal class InMemoryJobStore : IJobStore, ISingletonDependency
+{
+ private readonly List _memoryJobStore;
+
+ public InMemoryJobStore()
+ {
+ _memoryJobStore = new List();
+ }
+
+ public Task> GetAllPeriodTasksAsync(CancellationToken cancellationToken = default)
+ {
+ var jobs = _memoryJobStore
+ .Where(x => x.JobType == JobType.Period && x.Status == JobStatus.Running)
+ .OrderByDescending(x => x.Priority)
+ .ToList();
+
+ return Task.FromResult(jobs);
+ }
+
+ public Task> GetWaitingListAsync(int maxResultCount, CancellationToken cancellationToken = default)
+ {
+ var now = DateTime.Now;
+ var jobs = _memoryJobStore
+ .Where(x => !x.IsAbandoned && x.JobType != JobType.Period && x.Status == JobStatus.Running)
+ .OrderByDescending(x => x.Priority)
+ .ThenBy(x => x.TryCount)
+ .ThenBy(x => x.NextRunTime)
+ .Take(maxResultCount)
+ .ToList();
+
+ return Task.FromResult(jobs);
+ }
+
+ public Task FindAsync(Guid jobId)
+ {
+ var job = _memoryJobStore.FirstOrDefault(x => x.Id.Equals(jobId));
+ return Task.FromResult(job);
+ }
+
+ public Task StoreAsync(JobInfo jobInfo)
+ {
+ var job = _memoryJobStore.FirstOrDefault(x => x.Id.Equals(jobInfo.Id));
+ if (job != null)
+ {
+ job.NextRunTime = jobInfo.NextRunTime;
+ job.LastRunTime = jobInfo.LastRunTime;
+ job.Status = jobInfo.Status;
+ job.TriggerCount = jobInfo.TriggerCount;
+ job.TryCount = jobInfo.TryCount;
+ job.IsAbandoned = jobInfo.IsAbandoned;
+ }
+ else
+ {
+ _memoryJobStore.Add(jobInfo);
+ }
+ return Task.CompletedTask;
+ }
+
+ public Task StoreLogAsync(JobEventData eventData)
+ {
+ return Task.CompletedTask;
+ }
+
+ public Task CleanupAsync(int maxResultCount, TimeSpan jobExpiratime, CancellationToken cancellationToken = default)
+ {
+ var expiratime = DateTime.Now - jobExpiratime;
+
+ var expriaJobs = _memoryJobStore.Where(
+ x => x.Status == JobStatus.Completed &&
+ expiratime.CompareTo(x.LastRunTime ?? x.EndTime ?? x.CreationTime) <= 0)
+ .Take(maxResultCount);
+
+ _memoryJobStore.RemoveAll(expriaJobs);
+
+ return Task.CompletedTask;
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobEventProvider.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobEventProvider.cs
new file mode 100644
index 000000000..b0e6e5da2
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobEventProvider.cs
@@ -0,0 +1,41 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.BackgroundTasks.Internal;
+
+internal class JobEventProvider : IJobEventProvider, ISingletonDependency
+{
+ private readonly Lazy> _lazyEvents;
+ private List _events => _lazyEvents.Value;
+
+ private readonly IServiceProvider _serviceProvider;
+ private readonly AbpBackgroundTasksOptions _options;
+ public JobEventProvider(
+ IOptions options,
+ IServiceProvider serviceProvider)
+ {
+ _options = options.Value;
+ _serviceProvider = serviceProvider;
+
+ _lazyEvents = new Lazy>(CreateJobEvents);
+ }
+ public IReadOnlyCollection GetAll()
+ {
+ return _events.ToImmutableList();
+ }
+
+ private List CreateJobEvents()
+ {
+ var jobEvents = _options
+ .JobMonitors
+ .Select(p => _serviceProvider.GetRequiredService(p) as IJobEvent)
+ .ToList();
+
+ return jobEvents;
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobExecutedEvent.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobExecutedEvent.cs
new file mode 100644
index 000000000..dc64301b2
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobExecutedEvent.cs
@@ -0,0 +1,60 @@
+using Microsoft.Extensions.DependencyInjection;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.BackgroundTasks.Internal;
+
+internal class JobExecutedEvent : JobEventBase, ITransientDependency
+{
+ protected override async Task OnJobAfterExecutedAsync(JobEventContext context)
+ {
+ var store = context.ServiceProvider.GetRequiredService();
+
+ var job = await store.FindAsync(context.EventData.Key);
+ if (job != null)
+ {
+ job.TriggerCount += 1;
+ job.NextRunTime = context.EventData.NextRunTime;
+ job.LastRunTime = context.EventData.LastRunTime;
+ job.Result = context.EventData.Result;
+
+ // 一次性任务执行一次后标记为已完成
+ if (job.JobType == JobType.Once)
+ {
+ job.Status = JobStatus.Completed;
+ }
+
+ // 任务异常后可重试
+ if (context.EventData.Exception != null)
+ {
+ job.TryCount += 1;
+ job.Status = JobStatus.Running;
+ job.Result = context.EventData.Exception.Message;
+
+ if (job.TryCount > job.MaxTryCount)
+ {
+ job.Status = JobStatus.Stopped;
+ job.IsAbandoned = true;
+
+ await RemoveJobAsync(context, job);
+ }
+ }
+
+ // 所有任务达到上限则标记已完成
+ if (job.MaxCount > 0 && job.TriggerCount > job.MaxCount)
+ {
+ job.Status = JobStatus.Completed;
+
+ await RemoveJobAsync(context, job);
+ }
+
+ await store.StoreAsync(job);
+ }
+ }
+
+ private async Task RemoveJobAsync(JobEventContext context, JobInfo jobInfo)
+ {
+ var jobScheduler = context.ServiceProvider.GetRequiredService();
+ await jobScheduler.RemoveAsync(jobInfo);
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobLogEvent.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobLogEvent.cs
new file mode 100644
index 000000000..6fb015762
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobLogEvent.cs
@@ -0,0 +1,26 @@
+using Microsoft.Extensions.DependencyInjection;
+using System.Threading.Tasks;
+using Volo.Abp.Auditing;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.BackgroundTasks.Internal;
+
+///
+/// 存储任务日志
+///
+///
+/// 任务类型标记了 特性则不会记录日志
+///
+internal class JobLogEvent : JobEventBase, ITransientDependency
+{
+ protected async override Task OnJobAfterExecutedAsync(JobEventContext context)
+ {
+ if (context.EventData.Type.IsDefined(typeof(DisableAuditingAttribute), true))
+ {
+ return;
+ }
+ var store = context.ServiceProvider.GetRequiredService();
+
+ await store.StoreLogAsync(context.EventData);
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobEventBase.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobEventBase.cs
new file mode 100644
index 000000000..a7174915f
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobEventBase.cs
@@ -0,0 +1,58 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using System;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+public abstract class JobEventBase : IJobEvent
+{
+ public ILogger Logger { protected get; set; }
+ protected JobEventBase()
+ {
+ Logger = NullLogger.Instance;
+ }
+
+ public async Task OnJobAfterExecuted(JobEventContext context)
+ {
+ try
+ {
+ await OnJobAfterExecutedAsync(context);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("Failed to execute event, error:" + GetSourceException(ex).Message);
+ }
+ }
+
+ public async Task OnJobBeforeExecuted(JobEventContext context)
+ {
+ try
+ {
+ await OnJobBeforeExecutedAsync(context);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("Failed to execute preprocessing event, error:" + GetSourceException(ex).Message);
+ }
+ }
+
+ protected virtual Task OnJobAfterExecutedAsync(JobEventContext context)
+ {
+ return Task.CompletedTask;
+ }
+
+ protected virtual Task OnJobBeforeExecutedAsync(JobEventContext context)
+ {
+ return Task.CompletedTask;
+ }
+
+ protected virtual Exception GetSourceException(Exception exception)
+ {
+ if (exception.InnerException != null)
+ {
+ return GetSourceException(exception.InnerException);
+ }
+ return exception;
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobRunnableExecuter.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobRunnableExecuter.cs
new file mode 100644
index 000000000..24ad6721f
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobRunnableExecuter.cs
@@ -0,0 +1,55 @@
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.DistributedLocking;
+using Volo.Abp.MultiTenancy;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+public class JobRunnableExecuter : IJobRunnableExecuter, ISingletonDependency
+{
+ protected const string LockKeyFormat = "job:{0},key:{1}";
+
+ public async virtual Task ExecuteAsync(JobRunnableContext context)
+ {
+ Guid? tenantId = null;
+ if (context.JobData.TryGetValue(nameof(IMultiTenant.TenantId), out var tenant) &&
+ Guid.TryParse(tenant?.ToString(), out var tid))
+ {
+ tenantId = tid;
+ }
+
+ var currentTenant = context.ServiceProvider.GetRequiredService();
+ using (currentTenant.Change(tenantId))
+ {
+ context.JobData.TryGetValue(nameof(JobInfo.LockTimeOut), out var lockTime);
+
+ if (lockTime != null && (lockTime is int time && time > 0))
+ {
+ var jobId = context.JobData.GetOrDefault(nameof(JobInfo.Id));
+ var jobLockKey = string.Format(LockKeyFormat, context.JobType.Name, jobId);
+ var distributedLock = context.ServiceProvider.GetRequiredService();
+ await using (await distributedLock.TryAcquireAsync(jobLockKey, TimeSpan.FromSeconds(time)))
+ {
+ await InternalExecuteAsync(context);
+ }
+ }
+ else
+ {
+ await InternalExecuteAsync(context);
+ }
+ }
+ }
+
+ private async Task InternalExecuteAsync(JobRunnableContext context)
+ {
+ var jobRunnable = context.ServiceProvider.GetService(context.JobType);
+ if (jobRunnable == null)
+ {
+ jobRunnable = Activator.CreateInstance(context.JobType);
+ }
+ await ((IJobRunnable)jobRunnable).ExecuteAsync(context);
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/ConsoleJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/ConsoleJob.cs
new file mode 100644
index 000000000..a108d492c
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/ConsoleJob.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.BackgroundTasks.Primitives;
+
+public class ConsoleJob : IJobRunnable
+{
+ public Task ExecuteAsync(JobRunnableContext context)
+ {
+ Console.WriteLine($"This message comes from the job: {GetType()}");
+ return Task.CompletedTask;
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/EmailingJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/EmailingJob.cs
new file mode 100644
index 000000000..b8e3f95e8
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/EmailingJob.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.BackgroundTasks.Primitives;
+
+public class EmailingJob : IJobRunnable
+{
+ public virtual async Task ExecuteAsync(JobRunnableContext context)
+ {
+
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/README.md b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/README.md
new file mode 100644
index 000000000..a636695dc
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/README.md
@@ -0,0 +1,116 @@
+# LINGYUN.Abp.BackgroundTasks
+
+后台任务(队列)模块,Abp提供的后台作业与后台工作者不支持Cron表达式, 提供可管理的后台任务(队列)功能.
+
+实现了**Volo.Abp.BackgroundJobs.IBackgroundJobManager**, 意味着您也能通过框架后台作业接口添加新作业.
+
+## 任务类别
+
+* JobType.Once: 一次性任务, 此类型只会被执行一次, 适用于邮件通知等场景
+* JobType.Period: 周期性任务, 此类型任务会根据Cron表达式来决定运行方式, 适用于报表分析等场景
+* JobType.Persistent: 持续性任务, 此类型任务按照给定重复次数、重复间隔运行, 适用于接口压测等场景
+
+## 配置使用
+
+模块按需引用
+
+```csharp
+[DependsOn(typeof(AbpBackgroundTasksModule))]
+public class YouProjectModule : AbpModule
+{
+ // other
+}
+```
+
+```csharp
+public class DemoClass
+{
+ protected IServiceProvider ServiceProvider { get; }
+
+ public DemoClass(IServiceProvider serviceProvider)
+ {
+ ServiceProvider = serviceProvider;
+ }
+
+ public async Task Some()
+ {
+ var scheduler = ServiceProvider.GetRequiredService();
+
+ // 将周期性(5秒一次)任务添加到队列
+ await scheduler.QueueAsync(new JobInfo
+ {
+ Type = typeof(ConsoleJob).AssemblyQualifiedName,
+ Args = new Dictionary(),
+ Name = "Test-Console-Period",
+ Group = "Test",
+ Description = "Test-Console",
+ Id = Guid.NewGuid(),
+ JobType = JobType.Period,
+ Priority = Volo.Abp.BackgroundJobs.BackgroundJobPriority.Low,
+ Cron = "0/5 * * * * ? ",
+ TryCount = 10,
+ Status = JobStatus.Running,
+ });
+
+ // 将一次性任务添加到队列, 将在10(Interval)秒后被执行
+ await scheduler.QueueAsync(new JobInfo
+ {
+ Type = typeof(ConsoleJob).AssemblyQualifiedName,
+ Args = new Dictionary(),
+ Name = "Test-Console-Once",
+ Group = "Test",
+ Description = "Test-Console",
+ Id = Guid.NewGuid(),
+ JobType = JobType.Once,
+ Priority = Volo.Abp.BackgroundJobs.BackgroundJobPriority.Low,
+ Interval = 10,
+ TryCount = 10,
+ Status = JobStatus.Running,
+ });
+
+ // 将持续性任务添加到队列, 将在10(Interval)秒后被执行, 最大执行5(MaxCount)次
+ await scheduler.QueueAsync(new JobInfo
+ {
+ Type = typeof(ConsoleJob).AssemblyQualifiedName,
+ Args = new Dictionary(),
+ Name = "Test-Console-Persistent",
+ Group = "Test",
+ Description = "Test-Console",
+ Id = Guid.NewGuid(),
+ JobType = JobType.Persistent,
+ Priority = Volo.Abp.BackgroundJobs.BackgroundJobPriority.Low,
+ Interval = 10,
+ TryCount = 10,
+ MaxCount = 5,
+ Status = JobStatus.Running,
+ });
+
+ // 同样可以把框架后台作业添加到作业调度器中, 不需要更改使用习惯
+ var backgroundJobManager = ServiceProvider.GetRequiredService();
+ await jobManager.EnqueueAsync(
+ new SmsJobArgs
+ {
+ PhoneNumber = "13800138000",
+ Message = "来自框架的后台工作者"
+ },
+ BackgroundJobPriority.High,
+ TimeSpan.FromSeconds(10));
+ }
+}
+
+public class SmsJobArgs
+{
+ public string PhoneNumber { get; set; }
+ public string Message { get; set; }
+}
+
+public class SmsJob : AsyncBackgroundJob, ITransientDependency
+{
+ public override Task ExecuteAsync(SmsJobArgs args)
+ {
+ Console.WriteLine($"Send sms message: {args.Message}");
+
+ return Task.CompletedTask;
+ }
+}
+```
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/FodyWeavers.xml b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/FodyWeavers.xsd b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN.Abp.TaskManagement.Application.Contracts.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN.Abp.TaskManagement.Application.Contracts.csproj
new file mode 100644
index 000000000..d7b51dbfa
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN.Abp.TaskManagement.Application.Contracts.csproj
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
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
new file mode 100644
index 000000000..fe774ecec
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoCreateDto.cs
@@ -0,0 +1,17 @@
+namespace LINGYUN.Abp.TaskManagement;
+
+public class BackgroundJobInfoCreateDto : BackgroundJobInfoCreateOrUpdateDto
+{
+ ///
+ /// 任务名称
+ ///
+ public string Name { get; set; }
+ ///
+ /// 任务分组
+ ///
+ public string Group { get; set; }
+ ///
+ /// 任务类型
+ ///
+ public string Type { get; set; }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoCreateOrUpdateDto.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoCreateOrUpdateDto.cs
new file mode 100644
index 000000000..e2e17e87e
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoCreateOrUpdateDto.cs
@@ -0,0 +1,61 @@
+using LINGYUN.Abp.BackgroundTasks;
+using System;
+using Volo.Abp.Data;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public abstract class BackgroundJobInfoCreateOrUpdateDto
+{
+ ///
+ /// 是否启用
+ ///
+ public bool IsEnabled { get; set; }
+ ///
+ /// 任务参数
+ ///
+ public ExtraPropertyDictionary Args { get; set; }
+ ///
+ /// 描述
+ ///
+ public string Description { get; set; }
+ ///
+ /// 开始时间
+ ///
+ public DateTime BeginTime { get; set; }
+ ///
+ /// 结束时间
+ ///
+ public DateTime? EndTime { get; set; }
+ ///
+ /// 任务类别
+ ///
+ public JobType JobType { get; set; }
+ ///
+ /// Cron表达式,如果是持续任务需要指定
+ ///
+ public string Cron { get; set; }
+ ///
+ /// 失败重试上限
+ /// 默认:50
+ ///
+ public int MaxTryCount { get; set; }
+ ///
+ /// 最大执行次数
+ /// 默认:0, 无限制
+ ///
+ public int MaxCount { get; set; }
+ ///
+ /// 间隔时间,单位秒,与Cron表达式冲突
+ /// 默认: 300
+ ///
+ public int Interval { get; set; } = 300;
+ ///
+ /// 任务优先级
+ ///
+ public JobPriority Priority { get; set; }
+ ///
+ /// 任务独占超时时长(秒)
+ /// 0或更小不生效
+ ///
+ public int LockTimeOut { get; set; }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoDto.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoDto.cs
new file mode 100644
index 000000000..7506f0b38
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoDto.cs
@@ -0,0 +1,99 @@
+using LINGYUN.Abp.BackgroundTasks;
+using System;
+using System.Collections.Generic;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Data;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public class BackgroundJobInfoDto : ExtensibleAuditedEntityDto
+{
+ ///
+ /// 任务名称
+ ///
+ public string Name { get; set; }
+ ///
+ /// 任务分组
+ ///
+ public string Group { get; set; }
+ ///
+ /// 任务类型
+ ///
+ public string Type { get; set; }
+ ///
+ /// 返回参数
+ ///
+ public string Result { get; set; }
+ ///
+ /// 任务参数
+ ///
+ public ExtraPropertyDictionary Args { get; set; }
+ ///
+ /// 任务状态
+ ///
+ public JobStatus Status { get; set; }
+ ///
+ /// 描述
+ ///
+ public string Description { get; set; }
+ ///
+ /// 开始时间
+ ///
+ public DateTime BeginTime { get; set; }
+ ///
+ /// 结束时间
+ ///
+ public DateTime? EndTime { get; set; }
+ ///
+ /// 上次运行时间
+ ///
+ public DateTime? LastRunTime { get; set; }
+ ///
+ /// 下一次执行时间
+ ///
+ public DateTime? NextRunTime { get; set; }
+ ///
+ /// 任务类别
+ ///
+ public JobType JobType { get; set; }
+ ///
+ /// Cron表达式,如果是持续任务需要指定
+ ///
+ public string Cron { get; set; }
+ ///
+ /// 触发次数
+ ///
+ public int TriggerCount { get; set; }
+ ///
+ /// 失败重试次数
+ ///
+ public int TryCount { get; set; }
+ ///
+ /// 失败重试上限
+ /// 默认:50
+ ///
+ public int MaxTryCount { get; set; }
+ ///
+ /// 最大执行次数
+ /// 默认:0, 无限制
+ ///
+ public int MaxCount { get; set; }
+ ///
+ /// 连续失败且不会再次执行
+ ///
+ public bool IsAbandoned { get; set; }
+ ///
+ /// 间隔时间,单位秒,与Cron表达式冲突
+ /// 默认: 300
+ ///
+ public int Interval { get; set; } = 300;
+ ///
+ /// 任务优先级
+ ///
+ public JobPriority Priority { get; set; }
+ ///
+ /// 任务独占超时时长(秒)
+ /// 0或更小不生效
+ ///
+ public int LockTimeOut { get; set; }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoGetListInput.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoGetListInput.cs
new file mode 100644
index 000000000..1151449dc
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoGetListInput.cs
@@ -0,0 +1,65 @@
+using LINGYUN.Abp.BackgroundTasks;
+using System;
+using Volo.Abp.Application.Dtos;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public class BackgroundJobInfoGetListInput: PagedAndSortedResultRequestDto
+{
+ ///
+ /// 其他过滤条件
+ ///
+ public string Filter { get; set; }
+ ///
+ /// 任务名称
+ ///
+ public string Name { get; set; }
+ ///
+ /// 任务分组
+ ///
+ public string Group { get; set; }
+ ///
+ /// 任务类型
+ ///
+ public string Type { get; set; }
+ ///
+ /// 任务状态
+ ///
+ public JobStatus? Status { get; set; }
+ ///
+ /// 开始时间
+ ///
+ public DateTime? BeginTime { get; set; }
+ ///
+ /// 结束时间
+ ///
+ public DateTime? EndTime { get; set; }
+ ///
+ /// 上次起始触发时间
+ ///
+ public DateTime? BeginLastRunTime { get; set; }
+ ///
+ /// 上次截止触发时间
+ ///
+ public DateTime? EndLastRunTime { get; set; }
+ ///
+ /// 起始创建时间
+ ///
+ public DateTime? BeginCreationTime { get; set; }
+ ///
+ /// 截止创建时间
+ ///
+ public DateTime? EndCreationTime { get; set; }
+ ///
+ /// 是否已放弃任务
+ ///
+ public bool? IsAbandoned { get; set; }
+ ///
+ /// 是否持续性任务
+ ///
+ public bool? IsPeriod { get; set; }
+ ///
+ /// 优先级
+ ///
+ public JobPriority? Priority { get; set; }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoUpdateDto.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoUpdateDto.cs
new file mode 100644
index 000000000..17279a3b1
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobInfoUpdateDto.cs
@@ -0,0 +1,8 @@
+using Volo.Abp.Domain.Entities;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public class BackgroundJobInfoUpdateDto : BackgroundJobInfoCreateOrUpdateDto, IHasConcurrencyStamp
+{
+ public string ConcurrencyStamp { get; set; }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobLogDto.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobLogDto.cs
new file mode 100644
index 000000000..3411c5e9a
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobLogDto.cs
@@ -0,0 +1,14 @@
+using System;
+using Volo.Abp.Application.Dtos;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public class BackgroundJobLogDto : EntityDto
+{
+ public string JobName { get; set; }
+ public string JobGroup { get; set; }
+ public string JobType { get; set; }
+ public string Message { get; set; }
+ public DateTime RunTime { get; set; }
+ public string Exception { get; set; }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobLogGetListInput.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobLogGetListInput.cs
new file mode 100644
index 000000000..2967be0aa
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobLogGetListInput.cs
@@ -0,0 +1,36 @@
+using System;
+using Volo.Abp.Application.Dtos;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public class BackgroundJobLogGetListInput : PagedAndSortedResultRequestDto
+{
+ ///
+ /// 其他过滤条件
+ ///
+ public string Filter { get; set; }
+ ///
+ /// 存在异常
+ ///
+ public bool? HasExceptions { get; set; }
+ ///
+ /// 任务名称
+ ///
+ public string Name { get; set; }
+ ///
+ /// 任务分组
+ ///
+ public string Group { get; set; }
+ ///
+ /// 任务类型
+ ///
+ public string Type { get; set; }
+ ///
+ /// 开始触发时间
+ ///
+ public DateTime? BeginRunTime { get; set; }
+ ///
+ /// 结束触发时间
+ ///
+ public DateTime? EndRunTime { get; set; }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/IBackgroundJobInfoAppService.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/IBackgroundJobInfoAppService.cs
new file mode 100644
index 000000000..c0cf3a132
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/IBackgroundJobInfoAppService.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Threading.Tasks;
+using Volo.Abp.Application.Services;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public interface IBackgroundJobInfoAppService :
+ ICrudAppService<
+ BackgroundJobInfoDto,
+ Guid,
+ BackgroundJobInfoGetListInput,
+ BackgroundJobInfoCreateDto,
+ BackgroundJobInfoUpdateDto>
+{
+ Task TriggerAsync(Guid id);
+
+ Task PauseAsync(Guid id);
+
+ Task ResumeAsync(Guid id);
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/IBackgroundJobLogAppService.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/IBackgroundJobLogAppService.cs
new file mode 100644
index 000000000..cc41aae14
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/IBackgroundJobLogAppService.cs
@@ -0,0 +1,11 @@
+using Volo.Abp.Application.Services;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public interface IBackgroundJobLogAppService :
+ IReadOnlyAppService<
+ BackgroundJobLogDto,
+ long,
+ BackgroundJobLogGetListInput>
+{
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/Permissions/TaskManagementPermissions.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/Permissions/TaskManagementPermissions.cs
new file mode 100644
index 000000000..8ca7655fe
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/Permissions/TaskManagementPermissions.cs
@@ -0,0 +1,17 @@
+namespace LINGYUN.Abp.TaskManagement.Permissions;
+
+public static class TaskManagementPermissions
+{
+ public const string GroupName = "TaskManagement";
+
+ public static class BackgroundJobs
+ {
+ public const string Default = GroupName + ".BackgroundJobs";
+ public const string Create = Default + ".Create";
+ public const string Update = Default + ".Update";
+ public const string Delete = Default + ".Delete";
+ public const string Trigger = Default + ".Trigger";
+ public const string Pause = Default + ".Pause";
+ public const string Resume = Default + ".Resume";
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/TaskManagementApplicationContractsModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/TaskManagementApplicationContractsModule.cs
new file mode 100644
index 000000000..4288d4fdf
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/TaskManagementApplicationContractsModule.cs
@@ -0,0 +1,10 @@
+using Volo.Abp.Application;
+using Volo.Abp.Modularity;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+[DependsOn(typeof(TaskManagementDomainSharedModule))]
+[DependsOn(typeof(AbpDddApplicationContractsModule))]
+public class TaskManagementApplicationContractsModule : AbpModule
+{
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/FodyWeavers.xml b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/FodyWeavers.xsd b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN.Abp.TaskManagement.Application.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN.Abp.TaskManagement.Application.csproj
new file mode 100644
index 000000000..df4140ea7
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN.Abp.TaskManagement.Application.csproj
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
+
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
new file mode 100644
index 000000000..222683669
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobInfoAppService.cs
@@ -0,0 +1,161 @@
+using LINGYUN.Abp.BackgroundTasks;
+using LINGYUN.Abp.TaskManagement.Permissions;
+using Microsoft.AspNetCore.Authorization;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Data;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+[Authorize(TaskManagementPermissions.BackgroundJobs.Default)]
+public class BackgroundJobInfoAppService : TaskManagementApplicationService, IBackgroundJobInfoAppService
+{
+ protected BackgroundJobManager BackgroundJobManager { get; }
+ protected IBackgroundJobInfoRepository BackgroundJobInfoRepository { get; }
+
+ public BackgroundJobInfoAppService(
+ BackgroundJobManager backgroundJobManager,
+ IBackgroundJobInfoRepository backgroundJobInfoRepository)
+ {
+ BackgroundJobManager = backgroundJobManager;
+ BackgroundJobInfoRepository = backgroundJobInfoRepository;
+ }
+
+ [Authorize(TaskManagementPermissions.BackgroundJobs.Create)]
+ public virtual async Task CreateAsync(BackgroundJobInfoCreateDto input)
+ {
+ if (await BackgroundJobInfoRepository.CheckNameAsync(input.Name, input.Group))
+ {
+ throw new BusinessException(TaskManagementErrorCodes.JobNameAlreadyExists)
+ .WithData("Group", input.Group)
+ .WithData("Name", input.Name);
+ }
+
+ var backgroundJobInfo = new BackgroundJobInfo(
+ GuidGenerator.Create(),
+ input.Name,
+ input.Group,
+ input.Type,
+ input.Args,
+ input.BeginTime,
+ input.EndTime,
+ input.Priority,
+ input.MaxCount,
+ input.MaxTryCount);
+
+ UpdateByInput(backgroundJobInfo, input);
+
+ await BackgroundJobInfoRepository.InsertAsync(backgroundJobInfo, autoSave: true);
+
+ if (backgroundJobInfo.IsEnabled && backgroundJobInfo.JobType == JobType.Period)
+ {
+ await BackgroundJobManager.QueueAsync(backgroundJobInfo);
+ }
+
+ return ObjectMapper.Map(backgroundJobInfo);
+ }
+
+ [Authorize(TaskManagementPermissions.BackgroundJobs.Delete)]
+ public virtual async Task DeleteAsync(Guid id)
+ {
+ var backgroundJobInfo = await BackgroundJobInfoRepository.GetAsync(id);
+
+ await BackgroundJobManager.DeleteAsync(backgroundJobInfo);
+ }
+
+ public virtual async Task GetAsync(Guid id)
+ {
+ var backgroundJobInfo = await BackgroundJobInfoRepository.GetAsync(id);
+
+ return ObjectMapper.Map(backgroundJobInfo);
+ }
+
+ public virtual async Task> GetListAsync(BackgroundJobInfoGetListInput input)
+ {
+ var filter = new BackgroundJobInfoFilter
+ {
+ IsAbandoned = input.IsAbandoned,
+ IsPeriod = input.IsPeriod,
+ BeginCreationTime = input.BeginCreationTime,
+ EndCreationTime = input.EndCreationTime,
+ BeginLastRunTime = input.BeginLastRunTime,
+ EndLastRunTime = input.EndLastRunTime,
+ BeginTime = input.BeginTime,
+ EndTime = input.EndTime,
+ Filter = input.Filter,
+ Group = input.Group,
+ Name = input.Name,
+ Priority = input.Priority,
+ Status = input.Status,
+ Type = input.Type
+ };
+ var totalCount = await BackgroundJobInfoRepository.GetCountAsync(filter);
+ var backgroundJobInfos = await BackgroundJobInfoRepository.GetListAsync(
+ filter, input.Sorting, input.MaxResultCount, input.SkipCount);
+
+ return new PagedResultDto(totalCount,
+ ObjectMapper.Map, List>(backgroundJobInfos));
+ }
+
+ [Authorize(TaskManagementPermissions.BackgroundJobs.Pause)]
+ public virtual async Task PauseAsync(Guid id)
+ {
+ var backgroundJobInfo = await BackgroundJobInfoRepository.GetAsync(id);
+
+ await BackgroundJobManager.PauseAsync(backgroundJobInfo);
+ }
+
+ [Authorize(TaskManagementPermissions.BackgroundJobs.Resume)]
+ public virtual async Task ResumeAsync(Guid id)
+ {
+ var backgroundJobInfo = await BackgroundJobInfoRepository.GetAsync(id);
+
+ await BackgroundJobManager.ResumeAsync(backgroundJobInfo);
+ }
+
+ [Authorize(TaskManagementPermissions.BackgroundJobs.Trigger)]
+ public virtual async Task TriggerAsync(Guid id)
+ {
+ var backgroundJobInfo = await BackgroundJobInfoRepository.GetAsync(id);
+
+ await BackgroundJobManager.TriggerAsync(backgroundJobInfo);
+ }
+
+ [Authorize(TaskManagementPermissions.BackgroundJobs.Update)]
+ public virtual async Task UpdateAsync(Guid id, BackgroundJobInfoUpdateDto input)
+ {
+ var backgroundJobInfo = await BackgroundJobInfoRepository.GetAsync(id);
+
+ var resetJob = backgroundJobInfo.JobType == input.JobType;
+
+ UpdateByInput(backgroundJobInfo, input);
+
+ backgroundJobInfo.SetConcurrencyStampIfNotNull(input.ConcurrencyStamp);
+
+ await BackgroundJobManager.UpdateAsync(backgroundJobInfo, resetJob);
+
+ return ObjectMapper.Map(backgroundJobInfo);
+ }
+
+ protected virtual void UpdateByInput(BackgroundJobInfo backgroundJobInfo, BackgroundJobInfoCreateOrUpdateDto input)
+ {
+ backgroundJobInfo.IsEnabled = input.IsEnabled;
+ backgroundJobInfo.LockTimeOut = input.LockTimeOut;
+ backgroundJobInfo.Description = input.Description;
+ switch (input.JobType)
+ {
+ case JobType.Once:
+ backgroundJobInfo.SetOnceJob(input.Interval);
+ break;
+ case JobType.Persistent:
+ backgroundJobInfo.SetPersistentJob(input.Interval);
+ break;
+ case JobType.Period:
+ backgroundJobInfo.SetPeriodJob(input.Cron);
+ break;
+ }
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationMapperProfile.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationMapperProfile.cs
new file mode 100644
index 000000000..11468eb23
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationMapperProfile.cs
@@ -0,0 +1,11 @@
+using AutoMapper;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public class TaskManagementApplicationMapperProfile : Profile
+{
+ public TaskManagementApplicationMapperProfile()
+ {
+ CreateMap();
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationModule.cs
new file mode 100644
index 000000000..3bc12d61c
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationModule.cs
@@ -0,0 +1,22 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.Application;
+using Volo.Abp.AutoMapper;
+using Volo.Abp.Modularity;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+[DependsOn(typeof(TaskManagementApplicationContractsModule))]
+[DependsOn(typeof(TaskManagementDomainModule))]
+[DependsOn(typeof(AbpDddApplicationModule))]
+public class TaskManagementApplicationModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ context.Services.AddAutoMapperObjectMapper();
+
+ Configure(options =>
+ {
+ options.AddProfile(validate: true);
+ });
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationService.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationService.cs
new file mode 100644
index 000000000..6ca7ebba1
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationService.cs
@@ -0,0 +1,13 @@
+using LINGYUN.Abp.TaskManagement.Localization;
+using Volo.Abp.Application.Services;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public abstract class TaskManagementApplicationService : ApplicationService
+{
+ protected TaskManagementApplicationService()
+ {
+ LocalizationResource = typeof(TaskManagementResource);
+ ObjectMapperContext = typeof(TaskManagementApplicationModule);
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/FodyWeavers.xml b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/FodyWeavers.xsd b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN.Abp.TaskManagement.Domain.Shared.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN.Abp.TaskManagement.Domain.Shared.csproj
new file mode 100644
index 000000000..a268776f7
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN.Abp.TaskManagement.Domain.Shared.csproj
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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
new file mode 100644
index 000000000..bc316921f
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/BackgroundJobInfoConsts.cs
@@ -0,0 +1,10 @@
+namespace LINGYUN.Abp.TaskManagement;
+
+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 MaxTypeLength { get; set; } = 200;
+ public static int MaxDescriptionLength { get; set; } = 255;
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/BackgroundJobLogConsts.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/BackgroundJobLogConsts.cs
new file mode 100644
index 000000000..618438e20
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/BackgroundJobLogConsts.cs
@@ -0,0 +1,7 @@
+namespace LINGYUN.Abp.TaskManagement;
+
+public static class BackgroundJobLogConsts
+{
+ public static int MaxMessageLength { get; set; } = 1000;
+ public static int MaxExceptionLength { get; set; } = 2000;
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/en.json b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/en.json
new file mode 100644
index 000000000..10f2dda00
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/en.json
@@ -0,0 +1,6 @@
+{
+ "culture": "en",
+ "texts": {
+ "Permission:TaskManagement": "TaskManagement"
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/zh-Hans.json b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/zh-Hans.json
new file mode 100644
index 000000000..5b3611e36
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/zh-Hans.json
@@ -0,0 +1,6 @@
+{
+ "culture": "zh-Hans",
+ "texts": {
+ "Permission:TaskManagement": "任务管理"
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/TaskManagementResource.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/TaskManagementResource.cs
new file mode 100644
index 000000000..9e8624631
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/TaskManagementResource.cs
@@ -0,0 +1,8 @@
+using Volo.Abp.Localization;
+
+namespace LINGYUN.Abp.TaskManagement.Localization;
+
+[LocalizationResourceName("TaskManagement")]
+public class TaskManagementResource
+{
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/TaskManagementDomainSharedModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/TaskManagementDomainSharedModule.cs
new file mode 100644
index 000000000..02c1252b3
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/TaskManagementDomainSharedModule.cs
@@ -0,0 +1,34 @@
+using LINGYUN.Abp.BackgroundTasks;
+using LINGYUN.Abp.TaskManagement.Localization;
+using Volo.Abp.Localization;
+using Volo.Abp.Localization.ExceptionHandling;
+using Volo.Abp.Modularity;
+using Volo.Abp.Validation;
+using Volo.Abp.VirtualFileSystem;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+[DependsOn(typeof(AbpValidationModule))]
+[DependsOn(typeof(AbpBackgroundTasksAbstractionsModule))]
+public class TaskManagementDomainSharedModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.FileSets.AddEmbedded();
+ });
+
+ Configure(options =>
+ {
+ options.Resources
+ .Add()
+ .AddVirtualJson("/LINGYUN/Abp/TaskManagement/Localization/Resources");
+ });
+
+ Configure(options =>
+ {
+ options.MapCodeNamespace(TaskManagementErrorCodes.Namespace, typeof(TaskManagementResource));
+ });
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/TaskManagementErrorCodes.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/TaskManagementErrorCodes.cs
new file mode 100644
index 000000000..faa4bb6af
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/TaskManagementErrorCodes.cs
@@ -0,0 +1,9 @@
+namespace LINGYUN.Abp.TaskManagement
+{
+ public static class TaskManagementErrorCodes
+ {
+ public const string Namespace = "TaskManagement";
+
+ public const string JobNameAlreadyExists = Namespace + ":01000";
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/FodyWeavers.xml b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/FodyWeavers.xsd b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN.Abp.TaskManagement.Domain.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN.Abp.TaskManagement.Domain.csproj
new file mode 100644
index 000000000..7b045dcbe
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN.Abp.TaskManagement.Domain.csproj
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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
new file mode 100644
index 000000000..4704f65b9
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobInfo.cs
@@ -0,0 +1,162 @@
+using LINGYUN.Abp.BackgroundTasks;
+using System;
+using System.Collections.Generic;
+using Volo.Abp.Data;
+using Volo.Abp.Domain.Entities.Auditing;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public class BackgroundJobInfo : AuditedAggregateRoot
+{
+ ///
+ /// 任务名称
+ ///
+ public virtual string Name { get; protected set; }
+ ///
+ /// 任务分组
+ ///
+ public virtual string Group { get; protected set; }
+ ///
+ /// 任务类型
+ ///
+ public virtual string Type { get; protected set; }
+ ///
+ /// 任务参数
+ ///
+ public virtual ExtraPropertyDictionary Args { get; protected set; }
+ ///
+ /// 任务状态
+ ///
+ public virtual JobStatus Status { get; protected set; }
+ ///
+ /// 是否启用
+ ///
+ public virtual bool IsEnabled { get; set; }
+ ///
+ /// 描述
+ ///
+ public virtual string Description { get; set; }
+ ///
+ /// 任务独占超时时长(秒)
+ /// 0或更小不生效
+ ///
+ public virtual int LockTimeOut { get; set; }
+ ///
+ /// 开始时间
+ ///
+ public virtual DateTime BeginTime { get; protected set; }
+ ///
+ /// 结束时间
+ ///
+ public virtual DateTime? EndTime { get; protected set; }
+ ///
+ /// 上次执行时间
+ ///
+ public virtual DateTime? LastRunTime { get; protected set; }
+ ///
+ /// 下次执行时间
+ ///
+ public virtual DateTime? NextRunTime { get; protected set; }
+ ///
+ /// 任务类别
+ ///
+ public virtual JobType JobType { get; protected set; }
+ ///
+ /// Cron表达式,如果是持续任务需要指定
+ ///
+ public virtual string Cron { get; protected set; }
+ ///
+ /// 任务优先级
+ ///
+ public virtual JobPriority Priority { get; protected set; }
+ ///
+ /// 触发次数
+ ///
+ public virtual int TriggerCount { get; set; }
+ ///
+ /// 失败重试次数
+ ///
+ public virtual int TryCount { get; set; }
+ ///
+ /// 失败重试上限
+ /// 默认:50
+ ///
+ public virtual int MaxTryCount { get; set; }
+ ///
+ /// 最大执行次数
+ /// 默认:0, 无限制
+ ///
+ public virtual int MaxCount { get; set; }
+ ///
+ /// 间隔时间,单位秒,与Cron表达式冲突
+ /// 默认: 300
+ ///
+ public virtual int Interval { get; protected set; }
+ ///
+ /// 连续失败且不会再次执行
+ ///
+ public virtual bool IsAbandoned { get; set; }
+
+ protected BackgroundJobInfo() { }
+
+ public BackgroundJobInfo(
+ Guid id,
+ string name,
+ string group,
+ string type,
+ IDictionary args,
+ DateTime beginTime,
+ DateTime? endTime = null,
+ JobPriority priority = JobPriority.Normal,
+ int maxCount = 0,
+ int maxTryCount = 50) : base(id)
+ {
+ Name = name;
+ Group = group;
+ Type = type;
+ Priority = priority;
+ BeginTime = beginTime;
+ EndTime = endTime;
+
+ MaxCount = maxCount;
+ MaxTryCount = maxTryCount;
+
+ Status = JobStatus.Running;
+
+ Args = new ExtraPropertyDictionary();
+ Args.AddIfNotContains(args);
+ }
+
+ public void SetPeriodJob(string cron)
+ {
+ Cron = cron;
+ JobType = JobType.Period;
+ }
+
+ public void SetOnceJob(int interval)
+ {
+ Interval = interval;
+ JobType = JobType.Once;
+ }
+
+ public void SetPersistentJob(int interval)
+ {
+ Interval = interval;
+ JobType = JobType.Persistent;
+ }
+
+ public void SetLastRunTime(DateTime? lastRunTime)
+ {
+ LastRunTime = lastRunTime;
+ }
+
+ public void SetNextRunTime(DateTime? nextRunTime)
+ {
+ NextRunTime = nextRunTime;
+ }
+
+ public void SetStatus(JobStatus status)
+ {
+ Status = status;
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobInfoFilter.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobInfoFilter.cs
new file mode 100644
index 000000000..53573fba8
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobInfoFilter.cs
@@ -0,0 +1,67 @@
+using LINGYUN.Abp.BackgroundTasks;
+using System;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+///
+/// 后台任务过滤
+///
+public class BackgroundJobInfoFilter
+{
+ ///
+ /// 其他过滤条件
+ ///
+ public string Filter { get; set; }
+ ///
+ /// 任务名称
+ ///
+ public string Name { get; set; }
+ ///
+ /// 任务分组
+ ///
+ public string Group { get; set; }
+ ///
+ /// 任务类型
+ ///
+ public string Type { get; set; }
+ ///
+ /// 任务状态
+ ///
+ public JobStatus? Status { get; set; }
+ ///
+ /// 开始时间
+ ///
+ public DateTime? BeginTime { get; set; }
+ ///
+ /// 结束时间
+ ///
+ public DateTime? EndTime { get; set; }
+ ///
+ /// 上次起始触发时间
+ ///
+ public DateTime? BeginLastRunTime { get; set; }
+ ///
+ /// 上次截止触发时间
+ ///
+ public DateTime? EndLastRunTime { get; set; }
+ ///
+ /// 起始创建时间
+ ///
+ public DateTime? BeginCreationTime { get; set; }
+ ///
+ /// 截止创建时间
+ ///
+ public DateTime? EndCreationTime { get; set; }
+ ///
+ /// 是否已放弃任务
+ ///
+ public bool? IsAbandoned { get; set; }
+ ///
+ /// 是否持续性任务
+ ///
+ public bool? IsPeriod { get; set; }
+ ///
+ /// 优先级
+ ///
+ public JobPriority? Priority { get; set; }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLog.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLog.cs
new file mode 100644
index 000000000..9ae5ca1d0
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLog.cs
@@ -0,0 +1,39 @@
+using System;
+using Volo.Abp.Domain.Entities;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public class BackgroundJobLog : Entity
+{
+ public virtual Guid? JobId { get; set; }
+ public virtual string JobName { get; protected set; }
+ public virtual string JobGroup { get; protected set; }
+ public virtual string JobType { get; protected set; }
+ public virtual string Message { get; protected set; }
+ public virtual DateTime RunTime { get; protected set; }
+ public virtual string Exception { get; protected set; }
+ protected BackgroundJobLog() { }
+ public BackgroundJobLog(string type, string group, string name)
+ {
+ JobType = type;
+ JobGroup = group;
+ JobName = name;
+ RunTime = DateTime.Now;
+ }
+
+ public BackgroundJobLog SetMessage(string message, Exception ex)
+ {
+ Message = message.Length > BackgroundJobLogConsts.MaxMessageLength
+ ? message.Substring(0, BackgroundJobLogConsts.MaxMessageLength - 1)
+ : message;
+
+ if (ex != null)
+ {
+ var errMsg = ex.ToString();
+ Exception = errMsg.Length > BackgroundJobLogConsts.MaxExceptionLength
+ ? errMsg.Substring(0, BackgroundJobLogConsts.MaxExceptionLength - 1)
+ : errMsg;
+ }
+ return this;
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLogFilter.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLogFilter.cs
new file mode 100644
index 000000000..99bbdd984
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLogFilter.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public class BackgroundJobLogFilter
+{
+ ///
+ /// 其他过滤条件
+ ///
+ public string Filter { get; set; }
+ ///
+ /// 存在异常
+ ///
+ public bool? HasExceptions { get; set; }
+ ///
+ /// 任务名称
+ ///
+ public string Name { get; set; }
+ ///
+ /// 任务分组
+ ///
+ public string Group { get; set; }
+ ///
+ /// 任务类型
+ ///
+ public string Type { get; set; }
+ ///
+ /// 开始触发时间
+ ///
+ public DateTime? BeginRunTime { get; set; }
+ ///
+ /// 结束触发时间
+ ///
+ public DateTime? EndRunTime { get; set; }
+}
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
new file mode 100644
index 000000000..06b39aaea
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobManager.cs
@@ -0,0 +1,86 @@
+using LINGYUN.Abp.BackgroundTasks;
+using System.Threading.Tasks;
+using Volo.Abp.Domain.Services;
+using Volo.Abp.ObjectMapping;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public class BackgroundJobManager : DomainService
+{
+ protected IObjectMapper ObjectMapper { get; }
+ protected IJobScheduler JobScheduler { get; }
+ protected IBackgroundJobInfoRepository BackgroundJobInfoRepository { get; }
+
+ public BackgroundJobManager(
+ IObjectMapper objectMapper,
+ IJobScheduler jobScheduler,
+ IBackgroundJobInfoRepository backgroundJobInfoRepository)
+ {
+ ObjectMapper = objectMapper;
+ JobScheduler = jobScheduler;
+ BackgroundJobInfoRepository = backgroundJobInfoRepository;
+ }
+
+ public virtual async Task CreateAsync(BackgroundJobInfo jobInfo)
+ {
+ await BackgroundJobInfoRepository.InsertAsync(jobInfo);
+
+ if (jobInfo.IsEnabled && jobInfo.JobType == JobType.Period)
+ {
+ var job = ObjectMapper.Map(jobInfo);
+ await JobScheduler.QueueAsync(job);
+ }
+
+ return jobInfo;
+ }
+
+ public virtual async Task UpdateAsync(BackgroundJobInfo jobInfo, bool resetJob = false)
+ {
+ await BackgroundJobInfoRepository.UpdateAsync(jobInfo);
+
+ if (!jobInfo.IsEnabled || resetJob)
+ {
+ var job = ObjectMapper.Map(jobInfo);
+ await JobScheduler.RemoveAsync(job);
+ }
+
+ if (resetJob && jobInfo.JobType == JobType.Period)
+ {
+ await QueueAsync(jobInfo);
+ }
+
+ return jobInfo;
+ }
+
+ public virtual async Task DeleteAsync(BackgroundJobInfo jobInfo)
+ {
+ var job = ObjectMapper.Map(jobInfo);
+ await JobScheduler.RemoveAsync(job);
+
+ await BackgroundJobInfoRepository.DeleteAsync(jobInfo);
+ }
+
+ public virtual async Task QueueAsync(BackgroundJobInfo jobInfo)
+ {
+ var job = ObjectMapper.Map(jobInfo);
+ await JobScheduler.QueueAsync(job);
+ }
+
+ public virtual async Task TriggerAsync(BackgroundJobInfo jobInfo)
+ {
+ var job = ObjectMapper.Map(jobInfo);
+ await JobScheduler.TriggerAsync(job);
+ }
+
+ public virtual async Task PauseAsync(BackgroundJobInfo jobInfo)
+ {
+ var job = ObjectMapper.Map(jobInfo);
+ await JobScheduler.PauseAsync(job);
+ }
+
+ public virtual async Task ResumeAsync(BackgroundJobInfo jobInfo)
+ {
+ var job = ObjectMapper.Map(jobInfo);
+ await JobScheduler.ResumeAsync(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
new file mode 100644
index 000000000..e5498ab6f
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobStore.cs
@@ -0,0 +1,135 @@
+using LINGYUN.Abp.BackgroundTasks;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.ObjectMapping;
+using Volo.Abp.Uow;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+[Dependency(ReplaceServices = true)]
+public class BackgroundJobStore : IJobStore, ITransientDependency
+{
+ protected IObjectMapper ObjectMapper { get; }
+ protected IBackgroundJobInfoRepository JobInfoRepository { get; }
+ protected IBackgroundJobLogRepository JobLogRepository { get; }
+
+ public BackgroundJobStore(
+ IObjectMapper objectMapper,
+ IBackgroundJobInfoRepository jobInfoRepository,
+ IBackgroundJobLogRepository jobLogRepository)
+ {
+ ObjectMapper = objectMapper;
+ JobInfoRepository = jobInfoRepository;
+ JobLogRepository = jobLogRepository;
+ }
+
+ public async virtual Task> GetAllPeriodTasksAsync(CancellationToken cancellationToken = default)
+ {
+ var jobInfos = await JobInfoRepository.GetAllPeriodTasksAsync(cancellationToken);
+
+ return ObjectMapper.Map, List>(jobInfos);
+ }
+
+ public async virtual Task> GetWaitingListAsync(int maxResultCount, CancellationToken cancellationToken = default)
+ {
+ var jobInfos = await JobInfoRepository.GetWaitingListAsync(maxResultCount, cancellationToken);
+
+ return ObjectMapper.Map, List>(jobInfos);
+ }
+
+ public async virtual Task FindAsync(Guid jobId)
+ {
+ var jobInfo = await JobInfoRepository.FindAsync(jobId);
+
+ return ObjectMapper.Map(jobInfo);
+ }
+
+ [UnitOfWork]
+ public async virtual Task StoreAsync(JobInfo jobInfo)
+ {
+ var backgroundJobInfo = await JobInfoRepository.FindAsync(jobInfo.Id);
+ if (backgroundJobInfo != null)
+ {
+ backgroundJobInfo.SetNextRunTime(jobInfo.NextRunTime);
+ backgroundJobInfo.SetLastRunTime(jobInfo.LastRunTime);
+ backgroundJobInfo.SetStatus(jobInfo.Status);
+ backgroundJobInfo.TriggerCount = jobInfo.TriggerCount;
+ backgroundJobInfo.TryCount = jobInfo.TryCount;
+ backgroundJobInfo.IsAbandoned = jobInfo.IsAbandoned;
+
+ await JobInfoRepository.UpdateAsync(backgroundJobInfo);
+ }
+ else
+ {
+ backgroundJobInfo = new BackgroundJobInfo(
+ jobInfo.Id,
+ jobInfo.Name,
+ jobInfo.Group,
+ jobInfo.Type,
+ jobInfo.Args,
+ jobInfo.BeginTime,
+ jobInfo.EndTime,
+ jobInfo.Priority,
+ jobInfo.MaxCount,
+ jobInfo.MaxTryCount);
+
+ backgroundJobInfo.SetNextRunTime(jobInfo.NextRunTime);
+ backgroundJobInfo.SetLastRunTime(jobInfo.LastRunTime);
+ backgroundJobInfo.SetStatus(jobInfo.Status);
+ backgroundJobInfo.TriggerCount = jobInfo.TriggerCount;
+ backgroundJobInfo.IsAbandoned = jobInfo.IsAbandoned;
+ backgroundJobInfo.TryCount = jobInfo.TryCount;
+ backgroundJobInfo.LockTimeOut = jobInfo.LockTimeOut;
+ backgroundJobInfo.Description = jobInfo.Description;
+ switch (jobInfo.JobType)
+ {
+ case JobType.Once:
+ backgroundJobInfo.SetOnceJob(jobInfo.Interval);
+ break;
+ case JobType.Persistent:
+ backgroundJobInfo.SetPersistentJob(jobInfo.Interval);
+ break;
+ case JobType.Period:
+ backgroundJobInfo.SetPeriodJob(jobInfo.Cron);
+ break;
+ }
+
+ await JobInfoRepository.InsertAsync(backgroundJobInfo);
+ }
+ }
+
+ [UnitOfWork]
+ public async virtual Task StoreLogAsync(JobEventData eventData)
+ {
+ var jogLog = new BackgroundJobLog(
+ eventData.Type.Name,
+ eventData.Group,
+ eventData.Name)
+ {
+ JobId = eventData.Key
+ };
+
+ jogLog.SetMessage(
+ eventData.Exception == null ? eventData.Result ?? "OK" : "Failed",
+ eventData.Exception);
+
+ await JobLogRepository.InsertAsync(jogLog);
+ }
+
+ [UnitOfWork]
+ public async virtual Task CleanupAsync(
+ int maxResultCount,
+ TimeSpan jobExpiratime,
+ CancellationToken cancellationToken = default)
+ {
+ var jobs = await JobInfoRepository.GetExpiredJobsAsync(
+ 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
new file mode 100644
index 000000000..bffca21b9
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/IBackgroundJobInfoRepository.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.Domain.Repositories;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public interface IBackgroundJobInfoRepository : IRepository
+{
+ Task CheckNameAsync(
+ string group,
+ string name,
+ CancellationToken cancellationToken = default);
+ ///
+ /// 获取过期任务列表
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> GetExpiredJobsAsync(
+ int maxResultCount,
+ TimeSpan jobExpiratime,
+ CancellationToken cancellationToken = default);
+ ///
+ /// 获取所有周期性任务
+ /// 指定了Cron表达式的任务需要作为持续性任务交给任务引擎
+ ///
+ ///
+ Task> GetAllPeriodTasksAsync(
+ CancellationToken cancellationToken = default);
+ ///
+ /// 获取等待入队的任务列表
+ ///
+ ///
+ ///
+ ///
+ Task> GetWaitingListAsync(
+ int maxResultCount,
+ CancellationToken cancellationToken = default);
+ ///
+ /// 获取过滤后的任务数量
+ ///
+ ///
+ ///
+ ///
+ Task GetCountAsync(
+ BackgroundJobInfoFilter filter,
+ CancellationToken cancellationToken = default);
+ ///
+ /// 获取过滤后的任务列表
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> GetListAsync(
+ BackgroundJobInfoFilter filter,
+ string sorting = nameof(BackgroundJobInfo.Name),
+ int maxResultCount = 10,
+ int skipCount = 0,
+ CancellationToken cancellationToken = default);
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/IBackgroundJobLogRepository.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/IBackgroundJobLogRepository.cs
new file mode 100644
index 000000000..e9036a51a
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/IBackgroundJobLogRepository.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.Domain.Repositories;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public interface IBackgroundJobLogRepository : IRepository
+{
+ ///
+ /// 获取过滤后的任务日志数量
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task GetCountAsync(
+ BackgroundJobLogFilter filter,
+ Guid? jobId = null,
+ CancellationToken cancellationToken = default);
+ ///
+ /// 获取过滤后的任务日志列表
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> GetListAsync(
+ BackgroundJobLogFilter filter,
+ Guid? jobId = null,
+ string sorting = nameof(BackgroundJobLog.RunTime),
+ int maxResultCount = 10,
+ int skipCount = 0,
+ CancellationToken cancellationToken = default);
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/TaskManagementDbProperties.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/TaskManagementDbProperties.cs
new file mode 100644
index 000000000..a396d4036
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/TaskManagementDbProperties.cs
@@ -0,0 +1,11 @@
+namespace LINGYUN.Abp.TaskManagement;
+
+public static class TaskManagementDbProperties
+{
+ public static string DbTablePrefix { get; set; } = "TK_";
+
+ public static string DbSchema { get; set; } = null;
+
+
+ public const string ConnectionStringName = "TaskManagement";
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/TaskManagementDomainMapperProfile.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/TaskManagementDomainMapperProfile.cs
new file mode 100644
index 000000000..e5e133e55
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/TaskManagementDomainMapperProfile.cs
@@ -0,0 +1,12 @@
+using AutoMapper;
+using LINGYUN.Abp.BackgroundTasks;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public class TaskManagementDomainMapperProfile : Profile
+{
+ public TaskManagementDomainMapperProfile()
+ {
+ CreateMap();
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/TaskManagementDomainModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/TaskManagementDomainModule.cs
new file mode 100644
index 000000000..2d75c167c
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/TaskManagementDomainModule.cs
@@ -0,0 +1,24 @@
+using LINGYUN.Abp.BackgroundTasks;
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.AutoMapper;
+using Volo.Abp.Domain;
+using Volo.Abp.Modularity;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+[DependsOn(typeof(TaskManagementDomainSharedModule))]
+[DependsOn(typeof(AbpAutoMapperModule))]
+[DependsOn(typeof(AbpDddDomainModule))]
+[DependsOn(typeof(AbpBackgroundTasksModule))]
+public class TaskManagementDomainModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ context.Services.AddAutoMapperObjectMapper();
+
+ Configure(options =>
+ {
+ options.AddProfile(validate: true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/FodyWeavers.xml b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/FodyWeavers.xsd b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN.Abp.TaskManagement.EntityFrameworkCore.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN.Abp.TaskManagement.EntityFrameworkCore.csproj
new file mode 100644
index 000000000..60375de9f
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN.Abp.TaskManagement.EntityFrameworkCore.csproj
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ net6.0
+
+
+
+
+
+
+
+
+
+
+
+
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
new file mode 100644
index 000000000..8cc7bc601
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/EfCoreBackgroundJobInfoRepository.cs
@@ -0,0 +1,124 @@
+using LINGYUN.Abp.BackgroundTasks;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Dynamic.Core;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
+using Volo.Abp.EntityFrameworkCore;
+using Volo.Abp.Timing;
+
+namespace LINGYUN.Abp.TaskManagement.EntityFrameworkCore;
+
+public class EfCoreBackgroundJobInfoRepository :
+ EfCoreRepository,
+ IBackgroundJobInfoRepository
+{
+ protected IClock Clock { get; }
+
+ public EfCoreBackgroundJobInfoRepository(
+ IClock clock,
+ IDbContextProvider dbContextProvider)
+ : base(dbContextProvider)
+ {
+ Clock = clock;
+ }
+
+ public virtual async Task CheckNameAsync(
+ string group,
+ string name,
+ CancellationToken cancellationToken = default)
+ {
+ return await (await GetDbSetAsync())
+ .AllAsync(x => x.Group.Equals(group) && x.Name.Equals(name),
+ GetCancellationToken(cancellationToken));
+ }
+
+ public virtual async Task> GetExpiredJobsAsync(
+ int maxResultCount,
+ TimeSpan jobExpiratime,
+ CancellationToken cancellationToken = default)
+ {
+ var expiratime = Clock.Now - jobExpiratime;
+
+ return await (await GetDbSetAsync())
+ .Where(x => x.Status == JobStatus.Completed &&
+ DateTime.Compare(x.LastRunTime.Value, expiratime) <= 0)
+ .OrderBy(x => x.CreationTime)
+ .Take(maxResultCount)
+ .ToListAsync(GetCancellationToken(cancellationToken));
+ }
+
+ public virtual async Task> GetAllPeriodTasksAsync(CancellationToken cancellationToken = default)
+ {
+ return await (await GetDbSetAsync())
+ .Where(x => x.IsEnabled && !x.IsAbandoned)
+ .Where(x => x.JobType == JobType.Period && x.Status == JobStatus.Running)
+ .Where(x => x.TriggerCount < x.MaxCount && x.TryCount < x.MaxTryCount)
+ .OrderByDescending(x => x.Priority)
+ .ToListAsync(GetCancellationToken(cancellationToken));
+ }
+
+ public virtual async Task GetCountAsync(BackgroundJobInfoFilter filter, CancellationToken cancellationToken = default)
+ {
+ return await (await GetDbSetAsync())
+ .WhereIf(!filter.Type.IsNullOrWhiteSpace(), x => x.Type.Contains(filter.Type))
+ .WhereIf(!filter.Group.IsNullOrWhiteSpace(), x => x.Group.Equals(filter.Group))
+ .WhereIf(!filter.Name.IsNullOrWhiteSpace(), x => x.Name.Equals(filter.Name))
+ .WhereIf(!filter.Filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter.Filter) ||
+ x.Group.Contains(filter.Filter) || x.Type.Contains(filter.Filter) || x.Description.Contains(filter.Filter))
+ .WhereIf(filter.IsPeriod.HasValue && filter.IsPeriod.Value, x => x.JobType == JobType.Period)
+ .WhereIf(filter.IsPeriod.HasValue && !filter.IsPeriod.Value, x => x.JobType != JobType.Period)
+ .WhereIf(filter.Priority.HasValue, x => x.Priority == filter.Priority.Value)
+ .WhereIf(filter.Status.HasValue, x => x.Status == filter.Status.Value)
+ .WhereIf(filter.IsAbandoned.HasValue, x => x.IsAbandoned == filter.IsAbandoned.Value)
+ .WhereIf(filter.BeginLastRunTime.HasValue, x => filter.BeginLastRunTime.Value.CompareTo(x.LastRunTime) <= 0)
+ .WhereIf(filter.EndLastRunTime.HasValue, x => filter.EndLastRunTime.Value.CompareTo(x.LastRunTime) >= 0)
+ .WhereIf(filter.BeginTime.HasValue, x => x.BeginTime.CompareTo(x.BeginTime) >= 0)
+ .WhereIf(filter.EndTime.HasValue, x => filter.EndTime.Value.CompareTo(x.EndTime) >= 0)
+ .WhereIf(filter.BeginCreationTime.HasValue, x => x.CreationTime.CompareTo(filter.BeginCreationTime.Value) >= 0)
+ .WhereIf(filter.EndCreationTime.HasValue, x => x.CreationTime.CompareTo(filter.EndCreationTime.Value) <= 0)
+ .CountAsync(GetCancellationToken(cancellationToken));
+ }
+
+ public virtual async Task> GetListAsync(BackgroundJobInfoFilter filter, string sorting = "Name", int maxResultCount = 10, int skipCount = 0, CancellationToken cancellationToken = default)
+ {
+ return await (await GetDbSetAsync())
+ .WhereIf(!filter.Type.IsNullOrWhiteSpace(), x => x.Type.Contains(filter.Type))
+ .WhereIf(!filter.Group.IsNullOrWhiteSpace(), x => x.Group.Equals(filter.Group))
+ .WhereIf(!filter.Name.IsNullOrWhiteSpace(), x => x.Name.Equals(filter.Name))
+ .WhereIf(!filter.Filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter.Filter) ||
+ x.Group.Contains(filter.Filter) || x.Type.Contains(filter.Filter) || x.Description.Contains(filter.Filter))
+ .WhereIf(filter.IsPeriod.HasValue && filter.IsPeriod.Value, x => !string.IsNullOrWhiteSpace(x.Cron))
+ .WhereIf(filter.IsPeriod.HasValue && !filter.IsPeriod.Value, x => string.IsNullOrWhiteSpace(x.Cron))
+ .WhereIf(filter.Status.HasValue, x => x.Status == filter.Status.Value)
+ .WhereIf(filter.Priority.HasValue, x => x.Priority == filter.Priority.Value)
+ .WhereIf(filter.IsAbandoned.HasValue, x => x.IsAbandoned == filter.IsAbandoned.Value)
+ .WhereIf(filter.BeginLastRunTime.HasValue, x => filter.BeginLastRunTime.Value.CompareTo(x.LastRunTime) <= 0)
+ .WhereIf(filter.EndLastRunTime.HasValue, x => filter.EndLastRunTime.Value.CompareTo(x.LastRunTime) >= 0)
+ .WhereIf(filter.BeginTime.HasValue, x => x.BeginTime.CompareTo(x.BeginTime) >= 0)
+ .WhereIf(filter.EndTime.HasValue, x => filter.EndTime.Value.CompareTo(x.EndTime) >= 0)
+ .WhereIf(filter.BeginCreationTime.HasValue, x => x.CreationTime.CompareTo(filter.BeginCreationTime.Value) >= 0)
+ .WhereIf(filter.EndCreationTime.HasValue, x => x.CreationTime.CompareTo(filter.EndCreationTime.Value) <= 0)
+ .OrderBy(sorting ?? nameof(BackgroundJobInfo.Name))
+ .PageBy(skipCount, maxResultCount)
+ .ToListAsync(GetCancellationToken(cancellationToken));
+ }
+
+ public virtual async Task> GetWaitingListAsync(int maxResultCount, CancellationToken cancellationToken = default)
+ {
+ var now = Clock.Now;
+
+ return await (await GetDbSetAsync())
+ .Where(x => x.IsEnabled && !x.IsAbandoned)
+ .Where(x => x.JobType != JobType.Period && x.Status == JobStatus.Running)
+ .Where(x => x.TriggerCount < x.MaxCount && x.TryCount < x.MaxTryCount)
+ .OrderByDescending(x => x.Priority)
+ .ThenBy(x => x.TryCount)
+ .ThenBy(x => x.NextRunTime)
+ .Take(maxResultCount)
+ .ToListAsync(GetCancellationToken(cancellationToken));
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/EfCoreBackgroundJobLogRepository.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/EfCoreBackgroundJobLogRepository.cs
new file mode 100644
index 000000000..4508de1a0
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/EfCoreBackgroundJobLogRepository.cs
@@ -0,0 +1,63 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Dynamic.Core;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
+using Volo.Abp.EntityFrameworkCore;
+
+namespace LINGYUN.Abp.TaskManagement.EntityFrameworkCore;
+
+public class EfCoreBackgroundJobLogRepository :
+ EfCoreRepository,
+ IBackgroundJobLogRepository
+{
+ public EfCoreBackgroundJobLogRepository(
+ IDbContextProvider dbContextProvider)
+ : base(dbContextProvider)
+ {
+ }
+
+ public virtual async Task GetCountAsync(
+ BackgroundJobLogFilter filter,
+ Guid? jobId = null,
+ CancellationToken cancellationToken = default)
+ {
+ return await (await GetDbSetAsync())
+ .WhereIf(jobId.HasValue, x => x.JobId.Equals(jobId))
+ .WhereIf(!filter.Type.IsNullOrWhiteSpace(), x => x.JobType.Contains(filter.Type))
+ .WhereIf(!filter.Group.IsNullOrWhiteSpace(), x => x.JobGroup.Equals(filter.Group))
+ .WhereIf(!filter.Name.IsNullOrWhiteSpace(), x => x.JobName.Equals(filter.Name))
+ .WhereIf(!filter.Filter.IsNullOrWhiteSpace(), x => x.JobName.Contains(filter.Filter) ||
+ x.JobGroup.Contains(filter.Filter) || x.JobType.Contains(filter.Filter) || x.Message.Contains(filter.Filter))
+ .WhereIf(filter.HasExceptions.HasValue, x => !string.IsNullOrWhiteSpace(x.Exception))
+ .WhereIf(filter.BeginRunTime.HasValue, x => x.RunTime.CompareTo(filter.BeginRunTime.Value) >= 0)
+ .WhereIf(filter.EndRunTime.HasValue, x => x.RunTime.CompareTo(filter.EndRunTime.Value) <= 0)
+ .CountAsync(GetCancellationToken(cancellationToken));
+ }
+
+ public virtual async Task> GetListAsync(
+ BackgroundJobLogFilter filter,
+ Guid? jobId = null,
+ string sorting = nameof(BackgroundJobLog.RunTime),
+ int maxResultCount = 10,
+ int skipCount = 0,
+ CancellationToken cancellationToken = default)
+ {
+ return await (await GetDbSetAsync())
+ .WhereIf(jobId.HasValue, x => x.JobId.Equals(jobId))
+ .WhereIf(!filter.Type.IsNullOrWhiteSpace(), x => x.JobType.Contains(filter.Type))
+ .WhereIf(!filter.Group.IsNullOrWhiteSpace(), x => x.JobGroup.Equals(filter.Group))
+ .WhereIf(!filter.Name.IsNullOrWhiteSpace(), x => x.JobName.Equals(filter.Name))
+ .WhereIf(!filter.Filter.IsNullOrWhiteSpace(), x => x.JobName.Contains(filter.Filter) ||
+ x.JobGroup.Contains(filter.Filter) || x.JobType.Contains(filter.Filter) || x.Message.Contains(filter.Filter))
+ .WhereIf(filter.HasExceptions.HasValue, x => !string.IsNullOrWhiteSpace(x.Exception))
+ .WhereIf(filter.BeginRunTime.HasValue, x => x.RunTime.CompareTo(filter.BeginRunTime.Value) >= 0)
+ .WhereIf(filter.EndRunTime.HasValue, x => x.RunTime.CompareTo(filter.EndRunTime.Value) <= 0)
+ .OrderBy(sorting ?? nameof(BackgroundJobInfo.Name))
+ .PageBy(skipCount, maxResultCount)
+ .ToListAsync(GetCancellationToken(cancellationToken));
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/ITaskManagementDbContext.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/ITaskManagementDbContext.cs
new file mode 100644
index 000000000..c6284c0ab
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/ITaskManagementDbContext.cs
@@ -0,0 +1,9 @@
+using Volo.Abp.Data;
+using Volo.Abp.EntityFrameworkCore;
+
+namespace LINGYUN.Abp.TaskManagement.EntityFrameworkCore;
+
+[ConnectionStringName(TaskManagementDbProperties.ConnectionStringName)]
+public interface ITaskManagementDbContext :IEfCoreDbContext
+{
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementDbContext.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementDbContext.cs
new file mode 100644
index 000000000..a6d1f99ac
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementDbContext.cs
@@ -0,0 +1,20 @@
+using Microsoft.EntityFrameworkCore;
+using Volo.Abp.EntityFrameworkCore;
+
+namespace LINGYUN.Abp.TaskManagement.EntityFrameworkCore;
+
+public class TaskManagementDbContext : AbpDbContext, ITaskManagementDbContext
+{
+ public TaskManagementDbContext(
+ DbContextOptions options)
+ : base(options)
+ {
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ base.OnModelCreating(modelBuilder);
+
+ modelBuilder.ConfigureTaskManagement();
+ }
+}
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
new file mode 100644
index 000000000..c32fabef7
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementDbContextModelCreatingExtensions.cs
@@ -0,0 +1,81 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using Volo.Abp;
+using Volo.Abp.EntityFrameworkCore.Modeling;
+using Volo.Abp.EntityFrameworkCore.ValueComparers;
+using Volo.Abp.EntityFrameworkCore.ValueConverters;
+
+namespace LINGYUN.Abp.TaskManagement.EntityFrameworkCore;
+
+public static class TaskManagementDbContextModelCreatingExtensions
+{
+ public static void ConfigureTaskManagement(
+ this ModelBuilder builder,
+ Action optionsAction = null)
+ {
+ Check.NotNull(builder, nameof(builder));
+
+ var options = new TaskManagementModelBuilderConfigurationOptions(
+ TaskManagementDbProperties.DbTablePrefix,
+ TaskManagementDbProperties.DbSchema
+ );
+ optionsAction?.Invoke(options);
+
+ builder.Entity(b =>
+ {
+ b.ToTable(options.TablePrefix + "BackgroundJobs", options.Schema);
+
+ b.Property(p => p.Name)
+ .HasColumnName(nameof(BackgroundJobInfo.Name))
+ .HasMaxLength(BackgroundJobInfoConsts.MaxNameLength)
+ .IsRequired();
+ b.Property(p => p.Group)
+ .HasColumnName(nameof(BackgroundJobInfo.Group))
+ .HasMaxLength(BackgroundJobInfoConsts.MaxGroupLength)
+ .IsRequired();
+ b.Property(p => p.Type)
+ .HasColumnName(nameof(BackgroundJobInfo.Type))
+ .HasMaxLength(BackgroundJobInfoConsts.MaxTypeLength)
+ .IsRequired();
+ b.Property(p => p.Cron)
+ .HasColumnName(nameof(BackgroundJobInfo.Cron))
+ .HasMaxLength(BackgroundJobInfoConsts.MaxCronLength);
+ b.Property(p => p.Description)
+ .HasColumnName(nameof(BackgroundJobInfo.Description))
+ .HasMaxLength(BackgroundJobInfoConsts.MaxDescriptionLength);
+ b.Property(p => p.Args)
+ .HasColumnName(nameof(BackgroundJobInfo.Args))
+ .HasConversion(new ExtraPropertiesValueConverter(b.Metadata.ClrType))
+ .Metadata.SetValueComparer(new ExtraPropertyDictionaryValueComparer());
+
+ b.ConfigureByConvention();
+
+ b.HasIndex(p => new { p.Name, p.Group });
+ });
+
+ builder.Entity(b =>
+ {
+ b.ToTable(options.TablePrefix + "BackgroundJobLogs", options.Schema);
+
+ b.Property(p => p.JobName)
+ .HasColumnName(nameof(BackgroundJobLog.JobName))
+ .HasMaxLength(BackgroundJobInfoConsts.MaxNameLength);
+ b.Property(p => p.JobGroup)
+ .HasColumnName(nameof(BackgroundJobLog.JobGroup))
+ .HasMaxLength(BackgroundJobInfoConsts.MaxGroupLength);
+ b.Property(p => p.JobType)
+ .HasColumnName(nameof(BackgroundJobLog.JobType))
+ .HasMaxLength(BackgroundJobInfoConsts.MaxTypeLength);
+ b.Property(p => p.Message)
+ .HasColumnName(nameof(BackgroundJobLog.Message))
+ .HasMaxLength(BackgroundJobLogConsts.MaxMessageLength);
+ b.Property(p => p.Exception)
+ .HasColumnName(nameof(BackgroundJobLog.Exception))
+ .HasMaxLength(BackgroundJobLogConsts.MaxExceptionLength);
+
+ b.ConfigureByConvention();
+
+ b.HasIndex(p => new { p.JobGroup, p.JobName });
+ });
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementEntityFrameworkCoreModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementEntityFrameworkCoreModule.cs
new file mode 100644
index 000000000..f2edc4178
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementEntityFrameworkCoreModule.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.EntityFrameworkCore;
+using Volo.Abp.Modularity;
+
+namespace LINGYUN.Abp.TaskManagement.EntityFrameworkCore;
+
+[DependsOn(typeof(TaskManagementDomainModule))]
+[DependsOn(typeof(AbpEntityFrameworkCoreModule))]
+public class TaskManagementEntityFrameworkCoreModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ context.Services.AddAbpDbContext(options =>
+ {
+ options.AddRepository();
+ options.AddRepository();
+ });
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementModelBuilderConfigurationOptions.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementModelBuilderConfigurationOptions.cs
new file mode 100644
index 000000000..03b205c7c
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/TaskManagementModelBuilderConfigurationOptions.cs
@@ -0,0 +1,17 @@
+using JetBrains.Annotations;
+using Volo.Abp.EntityFrameworkCore.Modeling;
+
+namespace LINGYUN.Abp.TaskManagement.EntityFrameworkCore;
+
+public class TaskManagementModelBuilderConfigurationOptions : AbpModelBuilderConfigurationOptions
+{
+ public TaskManagementModelBuilderConfigurationOptions(
+ [NotNull] string tablePrefix = "",
+ [CanBeNull] string schema = null)
+ : base(
+ tablePrefix,
+ schema)
+ {
+
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/FodyWeavers.xml b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/FodyWeavers.xsd b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN.Abp.TaskManagement.HttpApi.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN.Abp.TaskManagement.HttpApi.csproj
new file mode 100644
index 000000000..128b311a8
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN.Abp.TaskManagement.HttpApi.csproj
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ net6.0
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/TaskManagementHttpApiModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/TaskManagementHttpApiModule.cs
new file mode 100644
index 000000000..b6d43f111
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/TaskManagementHttpApiModule.cs
@@ -0,0 +1,39 @@
+using LINGYUN.Abp.TaskManagement.Localization;
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.Localization;
+using Volo.Abp.Localization;
+using Volo.Abp.Modularity;
+using Volo.Abp.Validation.Localization;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+[DependsOn(typeof(TaskManagementApplicationContractsModule))]
+[DependsOn(typeof(AbpAspNetCoreMvcModule))]
+public class TaskManagementHttpApiModule : AbpModule
+{
+ public override void PreConfigureServices(ServiceConfigurationContext context)
+ {
+ PreConfigure(mvcBuilder =>
+ {
+ mvcBuilder.AddApplicationPartIfNotExists(typeof(TaskManagementHttpApiModule).Assembly);
+ });
+
+ PreConfigure(options =>
+ {
+ options.AddAssemblyResource(
+ typeof(TaskManagementResource),
+ typeof(TaskManagementApplicationContractsModule).Assembly);
+ });
+ }
+
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.Resources
+ .Get()
+ .AddBaseTypes(typeof(AbpValidationResource));
+ });
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN.Abp.TaskManagement.Quartz.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN.Abp.TaskManagement.Quartz.csproj
new file mode 100644
index 000000000..a079141f7
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN.Abp.TaskManagement.Quartz.csproj
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/IQuartzJobExecutorProvider.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/IQuartzJobExecutorProvider.cs
new file mode 100644
index 000000000..23f8d4b4f
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/IQuartzJobExecutorProvider.cs
@@ -0,0 +1,10 @@
+using Quartz;
+
+namespace LINGYUN.Abp.TaskManagement.Quartz;
+
+public interface IQuartzJobExecutorProvider
+{
+ IJobDetail CreateJob(JobInfo job);
+
+ ITrigger CreateTrigger(JobInfo job);
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/QuartzJobExecutorProvider.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/QuartzJobExecutorProvider.cs
new file mode 100644
index 000000000..97082fe02
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/QuartzJobExecutorProvider.cs
@@ -0,0 +1,20 @@
+using Quartz;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.TaskManagement.Quartz;
+
+public class QuartzJobExecutorProvider : IQuartzJobExecutorProvider, ISingletonDependency
+{
+ public IJobDetail CreateJob(JobInfo job)
+ {
+ throw new NotImplementedException();
+ }
+
+ public ITrigger CreateTrigger(JobInfo job)
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/QuartzJobScheduler.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/QuartzJobScheduler.cs
new file mode 100644
index 000000000..0e8a636b9
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/QuartzJobScheduler.cs
@@ -0,0 +1,63 @@
+using Quartz;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.TaskManagement.Quartz;
+public class QuartzJobScheduler : IJobScheduler
+{
+ protected IScheduler Scheduler { get; }
+
+ public QuartzJobScheduler(IScheduler scheduler)
+ {
+ Scheduler = scheduler;
+ }
+
+ public virtual async Task ExistsAsync(string group, string name)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public Task PauseAsync(string group, string name)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public Task QueueAsync(JobInfo job)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public Task RefreshAsync(JobInfo job)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public Task RemoveAsync(string group, string name)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public Task ResumeAsync(string group, string name)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public Task ShutdownAsync()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public Task StartAsync()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public Task StopAsync()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public Task TriggerAsync(JobInfo job)
+ {
+ throw new System.NotImplementedException();
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/QuartzJobSchedulerOptions.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/QuartzJobSchedulerOptions.cs
new file mode 100644
index 000000000..dbd0c774e
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Quartz/LINGYUN/Abp/TaskManagement/Quartz/QuartzJobSchedulerOptions.cs
@@ -0,0 +1,9 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace LINGYUN.Abp.TaskManagement.Quartz;
+
+internal class QuartzJobSchedulerOptions
+{
+}
diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Controllers/HomeController.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Controllers/HomeController.cs
new file mode 100644
index 000000000..f98d6c1ca
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Controllers/HomeController.cs
@@ -0,0 +1,12 @@
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+
+namespace LY.MicroService.TaskManagement.Controllers;
+
+public class HomeController : AbpController
+{
+ public IActionResult Index()
+ {
+ return Redirect("/swagger/index.html");
+ }
+}
diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Dockerfile b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Dockerfile
new file mode 100644
index 000000000..a38f2b0c8
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Dockerfile
@@ -0,0 +1,15 @@
+FROM mcr.microsoft.com/dotnet/aspnet:6.0
+LABEL maintainer="colin.in@foxmail.com"
+WORKDIR /app
+
+COPY . /app
+
+#东8区
+ENV TZ=Asia/Shanghai
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo '$TZ' > /etc/timezone
+
+EXPOSE 80/tcp
+VOLUME [ "./app/Logs" ]
+VOLUME [ "./app/Modules" ]
+
+ENTRYPOINT ["dotnet", "LY.MicroService.TaskManagement.HttpApi.Host.dll"]
diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/EntityFrameworkCore/TaskManagementMigrationsDbContext.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/EntityFrameworkCore/TaskManagementMigrationsDbContext.cs
new file mode 100644
index 000000000..229b8fdcc
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/EntityFrameworkCore/TaskManagementMigrationsDbContext.cs
@@ -0,0 +1,21 @@
+using LINGYUN.Abp.TaskManagement.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore;
+using Volo.Abp.EntityFrameworkCore;
+
+namespace LY.MicroService.TaskManagement.EntityFrameworkCore;
+
+public class TaskManagementMigrationsDbContext : AbpDbContext
+{
+ public TaskManagementMigrationsDbContext(DbContextOptions options)
+ : base(options)
+ {
+
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ base.OnModelCreating(modelBuilder);
+
+ modelBuilder.ConfigureTaskManagement();
+ }
+}
diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/EntityFrameworkCore/TaskManagementMigrationsDbContextFactory.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/EntityFrameworkCore/TaskManagementMigrationsDbContextFactory.cs
new file mode 100644
index 000000000..7ef7887cc
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/EntityFrameworkCore/TaskManagementMigrationsDbContextFactory.cs
@@ -0,0 +1,30 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Design;
+using Microsoft.Extensions.Configuration;
+using System.IO;
+
+namespace LY.MicroService.TaskManagement.EntityFrameworkCore;
+
+public class TaskManagementMigrationsDbContextFactory : IDesignTimeDbContextFactory
+{
+ public TaskManagementMigrationsDbContext CreateDbContext(string[] args)
+ {
+ var configuration = BuildConfiguration();
+ var connectionString = configuration.GetConnectionString("TaskManagement");
+
+ var builder = new DbContextOptionsBuilder()
+ .UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
+
+ return new TaskManagementMigrationsDbContext(builder.Options);
+ }
+
+ private static IConfigurationRoot BuildConfiguration()
+ {
+ var builder = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: false)
+ .AddJsonFile("appsettings.Development.json", optional: true);
+
+ return builder.Build();
+ }
+}
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
new file mode 100644
index 000000000..ccec8e8b2
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/LY.MicroService.TaskManagement.HttpApi.Host.csproj
@@ -0,0 +1,65 @@
+
+
+
+ False
+ False
+ False
+
+
+
+ False
+ False
+ False
+
+
+
+ net6.0
+ LY.MicroService.TaskManagement
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Program.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Program.cs
new file mode 100644
index 000000000..013d47509
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Program.cs
@@ -0,0 +1,44 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Serilog;
+
+namespace LY.MicroService.TaskManagement;
+
+public class Program
+{
+ public static int Main(string[] args)
+ {
+ try
+ {
+ var host = CreateHostBuilder(args).Build();
+ Log.Information("Starting web host.");
+ host.Run();
+ return 0;
+ }
+ finally
+ {
+ Log.CloseAndFlush();
+ }
+ }
+
+ internal static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup();
+ })
+ .ConfigureAppConfiguration((context, config) =>
+ {
+ var configuration = config.Build();
+ if (configuration.GetSection("AgileConfig").Exists())
+ {
+ config.AddAgileConfig(new AgileConfig.Client.ConfigClient(configuration));
+ }
+ })
+ .UseSerilog((context, config) =>
+ {
+ config.ReadFrom.Configuration(context.Configuration);
+ })
+ .UseAutofac();
+}
diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Properties/launchSettings.json b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Properties/launchSettings.json
new file mode 100644
index 000000000..38de94ebd
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Properties/launchSettings.json
@@ -0,0 +1,21 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:43766",
+ "sslPort": 0
+ }
+ },
+ "profiles": {
+ "LY.MicroService.TaskManagement.HttpApi.Host": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": false,
+ "applicationUrl": "http://127.0.0.1:30040",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Startup.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Startup.cs
new file mode 100644
index 000000000..35612530f
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Startup.cs
@@ -0,0 +1,30 @@
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
+using System.IO;
+using Volo.Abp.IO;
+using Volo.Abp.Modularity.PlugIns;
+
+namespace LY.MicroService.TaskManagement;
+
+public class Startup
+{
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddApplication(options =>
+ {
+ // 搜索 Modules 目录下所有文件作为插件
+ // 取消显示引用所有其他项目的模块,改为通过插件的形式引用
+ var pluginFolder = Path.Combine(
+ Directory.GetCurrentDirectory(), "Modules");
+ DirectoryHelper.CreateIfNotExists(pluginFolder);
+ options.PlugInSources.AddFolder(
+ pluginFolder,
+ SearchOption.AllDirectories);
+ });
+ }
+
+ public void Configure(IApplicationBuilder app)
+ {
+ app.InitializeApplication();
+ }
+}
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
new file mode 100644
index 000000000..6eafb7798
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.Configure.cs
@@ -0,0 +1,215 @@
+using LINGYUN.Abp.ExceptionHandling;
+using LINGYUN.Abp.ExceptionHandling.Emailing;
+using LINGYUN.Abp.Serilog.Enrichers.Application;
+using Medallion.Threading;
+using Medallion.Threading.Redis;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.AspNetCore.DataProtection;
+using Microsoft.Extensions.Caching.StackExchangeRedis;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.OpenApi.Models;
+using StackExchange.Redis;
+using System;
+using System.Text.Encodings.Web;
+using System.Text.Unicode;
+using Volo.Abp;
+using Volo.Abp.Auditing;
+using Volo.Abp.Caching;
+using Volo.Abp.EntityFrameworkCore;
+using Volo.Abp.Json;
+using Volo.Abp.Json.SystemTextJson;
+using Volo.Abp.Localization;
+using Volo.Abp.MultiTenancy;
+using Volo.Abp.VirtualFileSystem;
+
+namespace LY.MicroService.TaskManagement;
+
+public partial class TaskManagementHttpApiHostModule
+{
+ private void PreConfigureApp()
+ {
+ AbpSerilogEnrichersConsts.ApplicationName = "TaskManagement";
+ }
+
+ private void ConfigureDistributedLock(IServiceCollection services, IConfiguration configuration)
+ {
+ var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]);
+ services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase()));
+ }
+
+ private void ConfigureDbContext()
+ {
+ // 配置Ef
+ Configure(options =>
+ {
+ options.UseMySQL();
+ });
+ }
+
+ private void ConfigureJsonSerializer()
+ {
+ // 解决某些不支持类型的序列化
+ Configure(options =>
+ {
+ options.DefaultDateTimeFormat = "yyyy-MM-dd HH:mm:ss";
+ });
+ // 中文序列化的编码问题
+ Configure(options =>
+ {
+ options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
+ });
+ }
+
+ private void ConfigureExceptionHandling()
+ {
+ // 自定义需要处理的异常
+ Configure(options =>
+ {
+ // 加入需要处理的异常类型
+ options.Handlers.Add();
+ options.Handlers.Add();
+ options.Handlers.Add();
+ options.Handlers.Add();
+ options.Handlers.Add();
+ options.Handlers.Add();
+ });
+ // 自定义需要发送邮件通知的异常类型
+ Configure(options =>
+ {
+ // 是否发送堆栈信息
+ options.SendStackTrace = true;
+ // 未指定异常接收者的默认接收邮件
+ // 指定自己的邮件地址
+ });
+ }
+
+ private void ConfigureAuditing(IConfiguration configuration)
+ {
+ Configure(options =>
+ {
+ options.ApplicationName = "TaskManagement";
+ // 是否启用实体变更记录
+ var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged");
+ if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get())
+ {
+ options
+ .EntityHistorySelectors
+ .AddAllEntities();
+ }
+ });
+ }
+
+ private void ConfigureCaching(IConfiguration configuration)
+ {
+ Configure(options =>
+ {
+ // 最好统一命名,不然某个缓存变动其他应用服务有例外发生
+ options.KeyPrefix = "LINGYUN.Abp.Application";
+ // 滑动过期30天
+ options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30d);
+ // 绝对过期60天
+ options.GlobalCacheEntryOptions.AbsoluteExpiration = DateTimeOffset.Now.AddDays(60d);
+ });
+
+ Configure(options =>
+ {
+ var redisConfig = ConfigurationOptions.Parse(options.Configuration);
+ options.ConfigurationOptions = redisConfig;
+ options.InstanceName = configuration["Redis:InstanceName"];
+ });
+ }
+
+ private void ConfigureVirtualFileSystem()
+ {
+ Configure(options =>
+ {
+ options.FileSets.AddEmbedded("LINGYUN.Abp.TaskManagement");
+ });
+ }
+
+ private void ConfigureMultiTenancy(IConfiguration configuration)
+ {
+ // 多租户
+ Configure(options =>
+ {
+ options.IsEnabled = true;
+ });
+
+ var tenantResolveCfg = configuration.GetSection("App:Domains");
+ if (tenantResolveCfg.Exists())
+ {
+ Configure(options =>
+ {
+ var domains = tenantResolveCfg.Get();
+ foreach (var domain in domains)
+ {
+ options.AddDomainTenantResolver(domain);
+ }
+ });
+ }
+ }
+
+ private void ConfigureSwagger(IServiceCollection services)
+ {
+ // Swagger
+ services.AddSwaggerGen(
+ options =>
+ {
+ options.SwaggerDoc("v1", new OpenApiInfo { Title = "WorkflowManagement API", Version = "v1" });
+ options.DocInclusionPredicate((docName, description) => true);
+ options.CustomSchemaIds(type => type.FullName);
+ options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
+ {
+ Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
+ Name = "Authorization",
+ In = ParameterLocation.Header,
+ Scheme = "bearer",
+ Type = SecuritySchemeType.Http,
+ BearerFormat = "JWT"
+ });
+ options.AddSecurityRequirement(new OpenApiSecurityRequirement
+ {
+ {
+ new OpenApiSecurityScheme
+ {
+ Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
+ },
+ new string[] { }
+ }
+ });
+ });
+ }
+
+ private void ConfigureLocalization()
+ {
+ // 支持本地化语言类型
+ Configure(options =>
+ {
+ options.Languages.Add(new LanguageInfo("en", "en", "English"));
+ options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
+ // 动态语言支持
+ options.Resources.AddDynamic();
+ });
+ }
+
+ private void ConfigureSecurity(IServiceCollection services, IConfiguration configuration, bool isDevelopment = false)
+ {
+ services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+ .AddJwtBearer(options =>
+ {
+ options.Authority = configuration["AuthServer:Authority"];
+ options.RequireHttpsMetadata = false;
+ options.Audience = configuration["AuthServer:ApiName"];
+ });
+
+ if (!isDevelopment)
+ {
+ var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);
+ services
+ .AddDataProtection()
+ .SetApplicationName("LINGYUN.Abp.Application")
+ .PersistKeysToStackExchangeRedis(redis, "LINGYUN.Abp.Application:DataProtection:Protection-Keys");
+ }
+ }
+}
diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs
new file mode 100644
index 000000000..453210150
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs
@@ -0,0 +1,114 @@
+using LINGYUN.Abp.AuditLogging.Elasticsearch;
+using LINGYUN.Abp.BackgroundTasks.Quartz;
+using LINGYUN.Abp.Data.DbMigrator;
+using LINGYUN.Abp.ExceptionHandling.Emailing;
+using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore;
+using LINGYUN.Abp.MultiTenancy.DbFinder;
+using LINGYUN.Abp.Serilog.Enrichers.Application;
+using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using System.Globalization;
+using Volo.Abp;
+using Volo.Abp.AspNetCore.Authentication.JwtBearer;
+using Volo.Abp.AspNetCore.MultiTenancy;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Serilog;
+using Volo.Abp.Autofac;
+using Volo.Abp.Caching.StackExchangeRedis;
+using Volo.Abp.EntityFrameworkCore.MySQL;
+using Volo.Abp.FeatureManagement.EntityFrameworkCore;
+using Volo.Abp.Http.Client.IdentityModel.Web;
+using Volo.Abp.Modularity;
+using Volo.Abp.PermissionManagement.EntityFrameworkCore;
+using Volo.Abp.SettingManagement.EntityFrameworkCore;
+using Volo.Abp.Swashbuckle;
+using Volo.Abp.TenantManagement.EntityFrameworkCore;
+
+namespace LY.MicroService.TaskManagement;
+
+[DependsOn(
+ typeof(AbpSerilogEnrichersApplicationModule),
+ typeof(AbpSerilogEnrichersUniqueIdModule),
+ typeof(AbpAuditLoggingElasticsearchModule),
+ typeof(AbpAspNetCoreSerilogModule),
+ typeof(AbpEntityFrameworkCoreMySQLModule),
+ typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
+ typeof(AbpEmailingExceptionHandlingModule),
+ typeof(AbpHttpClientIdentityModelWebModule),
+ typeof(AbpAspNetCoreMultiTenancyModule),
+ typeof(AbpDbFinderMultiTenancyModule),
+ typeof(AbpBackgroundTasksQuartzModule),
+ //typeof(TaskManagementApplicationModule),
+ //typeof(TaskManagementHttpApiModule),
+ //typeof(TaskManagementEntityFrameworkCoreModule),
+ typeof(AbpFeatureManagementEntityFrameworkCoreModule),
+ typeof(AbpPermissionManagementEntityFrameworkCoreModule),
+ typeof(AbpSettingManagementEntityFrameworkCoreModule),
+ typeof(AbpTenantManagementEntityFrameworkCoreModule),
+ typeof(AbpLocalizationManagementEntityFrameworkCoreModule),
+ typeof(AbpDataDbMigratorModule),
+ typeof(AbpCachingStackExchangeRedisModule),
+ typeof(AbpAspNetCoreMvcModule),
+ typeof(AbpSwashbuckleModule),
+ typeof(AbpAutofacModule)
+ )]
+public partial class TaskManagementHttpApiHostModule : AbpModule
+{
+ public override void PreConfigureServices(ServiceConfigurationContext context)
+ {
+ PreConfigureApp();
+ }
+
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ var hostingEnvironment = context.Services.GetHostingEnvironment();
+ var configuration = context.Services.GetConfiguration();
+
+ ConfigureDbContext();
+ ConfigureLocalization();
+ ConfigureJsonSerializer();
+ ConfigureExceptionHandling();
+ ConfigureVirtualFileSystem();
+ ConfigureCaching(configuration);
+ ConfigureAuditing(configuration);
+ ConfigureMultiTenancy(configuration);
+ ConfigureSwagger(context.Services);
+ ConfigureDistributedLock(context.Services, configuration);
+ ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment());
+
+ // 开发取消权限检查
+ // context.Services.AddAlwaysAllowAuthorization();
+ }
+
+ public override void OnApplicationInitialization(ApplicationInitializationContext context)
+ {
+ var app = context.GetApplicationBuilder();
+ var env = context.GetEnvironment();
+
+ app.UseStaticFiles();
+ app.UseCorrelationId();
+ app.UseRouting();
+ app.UseCors();
+ app.UseAuthentication();
+ app.UseJwtTokenMiddleware();
+ app.UseMultiTenancy();
+ app.UseAbpRequestLocalization(options => options.SetDefaultCulture(CultureInfo.CurrentCulture.Name));
+ app.UseAuthorization();
+ app.UseSwagger();
+ app.UseAbpSwaggerUI(options =>
+ {
+ options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support Task Management API");
+
+ var configuration = context.GetConfiguration();
+ options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);
+ options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]);
+ options.OAuthScopes("TaskManagement");
+ });
+ app.UseAuditing();
+ app.UseAbpSerilogEnrichers();
+ app.UseConfiguredEndpoints();
+ }
+}
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
new file mode 100644
index 000000000..3315406f2
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.json
@@ -0,0 +1,118 @@
+{
+ "AgileConfig": {
+ "env": "DEV",
+ "appId": "LINGYUN.Abp.TaskManagement",
+ "secret": "1q2w3E*",
+ "nodes": "http://127.0.0.1:15000",
+ "name": "LINGYUN.Abp.TaskManagement",
+ "tag": "LINGYUN.Abp.TaskManagement"
+ },
+ "App": {
+ "TrackingEntitiesChanged": true
+ },
+ "CAP": {
+ "EventBus": {
+ "DefaultGroupName": "TaskManagement",
+ "Version": "v1",
+ "FailedRetryInterval": 300,
+ "FailedRetryCount": 10,
+ "CollectorCleaningInterval": 3600000
+ },
+ "MySql": {
+ "TableNamePrefix": "tsk",
+ "ConnectionString": "Server=localhost;Database=Platform;User Id=root;Password=123456"
+ },
+ "RabbitMQ": {
+ "HostName": "localhost",
+ "Port": 5672,
+ "UserName": "guest",
+ "Password": "guest",
+ "ExchangeName": "LINGYUN.Abp.Application",
+ "VirtualHost": "/"
+ }
+ },
+ "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",
+ "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",
+ "AbpLocalizationManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456",
+ "AbpSettingManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456",
+ "AbpTenantManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456"
+ },
+ "RemoteServices": {
+ "AbpOssManagement": {
+ "BaseUrl": "http://127.0.0.1:30025",
+ "IdentityClient": "InternalServiceClient",
+ "UseCurrentAccessToken": false
+ }
+ },
+ "IdentityClients": {
+ "InternalServiceClient": {
+ "Authority": "http://127.0.0.1:44385",
+ "RequireHttps": false,
+ "GrantType": "client_credentials",
+ "Scope": "lingyun-abp-application",
+ "ClientId": "InternalServiceClient",
+ "ClientSecret": "1q2w3E*"
+ }
+ },
+ "DistributedLock": {
+ "Redis": {
+ "Configuration": "127.0.0.1,defaultDatabase=15"
+ }
+ },
+ "Redis": {
+ "Configuration": "127.0.0.1,defaultDatabase=10",
+ "InstanceName": "LINGYUN.Abp.Application"
+ },
+ "AuthServer": {
+ "Authority": "http://127.0.0.1:44385/",
+ "ApiName": "lingyun-abp-application",
+ "SwaggerClientId": "InternalServiceClient",
+ "SwaggerClientSecret": "1q2w3E*"
+ },
+ "Logging": {
+ "Serilog": {
+ "Elasticsearch": {
+ "IndexFormat": "abp.dev.logging-{0:yyyy.MM.dd}"
+ }
+ }
+ },
+ "AuditLogging": {
+ "Elasticsearch": {
+ "IndexPrefix": "abp.dev.auditing"
+ }
+ },
+ "Elasticsearch": {
+ "NodeUris": "http://127.0.0.1:9200"
+ },
+ "Serilog": {
+ "MinimumLevel": {
+ "Default": "Debug",
+ "Override": {
+ "System": "Warning",
+ "Microsoft": "Warning",
+ "DotNetCore": "Debug"
+ }
+ },
+ "WriteTo": [
+ {
+ "Name": "Console",
+ "Args": {
+ "restrictedToMinimumLevel": "Debug",
+ "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}"
+ }
+ },
+ {
+ "Name": "Elasticsearch",
+ "Args": {
+ "nodeUris": "http://127.0.0.1:9200",
+ "indexFormat": "abp.dev.logging-{0:yyyy.MM.dd}",
+ "autoRegisterTemplate": true,
+ "autoRegisterTemplateVersion": "ESv7"
+ }
+ }
+ ]
+ }
+}
diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.json b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.json
new file mode 100644
index 000000000..67e1bc4bd
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.json
@@ -0,0 +1,80 @@
+{
+ "StringEncryption": {
+ "DefaultPassPhrase": "s46c5q55nxpeS8Ra",
+ "InitVectorBytes": "s83ng0abvd02js84",
+ "DefaultSalt": "sf&5)s3#"
+ },
+ "AllowedHosts": "*",
+ "Serilog": {
+ "MinimumLevel": {
+ "Default": "Debug",
+ "Override": {
+ "Microsoft.EntityFrameworkCore": "Debug",
+ "System": "Information",
+ "Microsoft": "Information"
+ }
+ },
+ "Enrich": [ "FromLogContext", "WithProcessId", "WithThreadId", "WithEnvironmentName", "WithMachineName", "WithApplicationName", "WithUniqueId" ],
+ "WriteTo": [
+ {
+ "Name": "Console",
+ "Args": {
+ "initialMinimumLevel": "Verbose",
+ "standardErrorFromLevel": "Verbose",
+ "restrictedToMinimumLevel": "Verbose",
+ "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}"
+ }
+ },
+ {
+ "Name": "File",
+ "Args": {
+ "path": "Logs/Debug-.log",
+ "restrictedToMinimumLevel": "Debug",
+ "rollingInterval": "Day",
+ "fileSizeLimitBytes": 5242880,
+ "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}"
+ }
+ },
+ {
+ "Name": "File",
+ "Args": {
+ "path": "Logs/Info-.log",
+ "restrictedToMinimumLevel": "Information",
+ "rollingInterval": "Day",
+ "fileSizeLimitBytes": 5242880,
+ "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}"
+ }
+ },
+ {
+ "Name": "File",
+ "Args": {
+ "path": "Logs/Warn-.log",
+ "restrictedToMinimumLevel": "Warning",
+ "rollingInterval": "Day",
+ "fileSizeLimitBytes": 5242880,
+ "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}"
+ }
+ },
+ {
+ "Name": "File",
+ "Args": {
+ "path": "Logs/Error-.log",
+ "restrictedToMinimumLevel": "Error",
+ "rollingInterval": "Day",
+ "fileSizeLimitBytes": 5242880,
+ "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}"
+ }
+ },
+ {
+ "Name": "File",
+ "Args": {
+ "path": "Logs/Fatal-.log",
+ "restrictedToMinimumLevel": "Fatal",
+ "rollingInterval": "Day",
+ "fileSizeLimitBytes": 5242880,
+ "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}"
+ }
+ }
+ ]
+ }
+}
diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/dapr.sh b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/dapr.sh
new file mode 100644
index 000000000..fa1450cf4
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/dapr.sh
@@ -0,0 +1 @@
+dapr run --app-id workflow --app-port 30040 -H 34178 -- dotnet run --no-build
\ No newline at end of file
From 44220eb2cc22b80e62c9c2fd7526bcbc7f9d3caa Mon Sep 17 00:00:00 2001
From: cKey <35512826+colinin@users.noreply.github.com>
Date: Sat, 8 Jan 2022 23:04:04 +0800
Subject: [PATCH 02/10] feat(tasks): if the task fails, recalculate the
priority
---
.../LINGYUN/Abp/BackgroundTasks/JobInfo.cs | 2 +-
.../LINGYUN.Abp.BackgroundTasks.Quartz/README.md | 2 +-
.../Abp/BackgroundTasks/IJobRunnableExecuter.cs | 0
.../BackgroundTasks/Internal/JobExecutedEvent.cs | 14 +++++++++++++-
.../LINGYUN.Abp.BackgroundTasks/README.md | 2 ++
5 files changed, 17 insertions(+), 3 deletions(-)
rename aspnet-core/modules/task-management/{LINGYUN.Abp.BackgroundTasks.Abstractions => LINGYUN.Abp.BackgroundTasks}/LINGYUN/Abp/BackgroundTasks/IJobRunnableExecuter.cs (100%)
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 ce724e44e..85246741a 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
@@ -62,7 +62,7 @@ public class JobInfo
///
public JobType JobType { get; set; } = JobType.Once;
///
- /// Cron表达式,如果是持续任务需要指定
+ /// Cron表达式,如果是周期性任务需要指定
///
public string Cron { get; set; }
///
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/README.md b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/README.md
index b1dd81e5b..84110905b 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/README.md
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/README.md
@@ -1,6 +1,6 @@
# LINGYUN.Abp.BackgroundTasks.Quartz
-后台任务(队列)模块的Quartz实现, 使用任务适配器来做到任务的幂等性控制.
+后台任务(队列)模块的Quartz实现.
并添加一个监听器用于通知管理者任务状态
## 配置使用
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobRunnableExecuter.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobRunnableExecuter.cs
similarity index 100%
rename from aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobRunnableExecuter.cs
rename to aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/IJobRunnableExecuter.cs
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobExecutedEvent.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobExecutedEvent.cs
index dc64301b2..4cbbc0fd9 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobExecutedEvent.cs
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobExecutedEvent.cs
@@ -28,9 +28,21 @@ internal class JobExecutedEvent : JobEventBase, ITransientDepe
if (context.EventData.Exception != null)
{
job.TryCount += 1;
+ // 将任务标记为运行中, 会被轮询重新进入队列
job.Status = JobStatus.Running;
job.Result = context.EventData.Exception.Message;
-
+
+ // 多次异常后需要重新计算优先级
+ if (job.TryCount <= (job.MaxTryCount / 2) &&
+ job.TryCount > (job.MaxTryCount / 3))
+ {
+ job.Priority = JobPriority.BelowNormal;
+ }
+ else if (job.TryCount > (job.MaxTryCount / 1.5))
+ {
+ job.Priority = JobPriority.Low;
+ }
+
if (job.TryCount > job.MaxTryCount)
{
job.Status = JobStatus.Stopped;
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/README.md b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/README.md
index a636695dc..b3a9bee08 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/README.md
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/README.md
@@ -50,6 +50,8 @@ public class DemoClass
Cron = "0/5 * * * * ? ",
TryCount = 10,
Status = JobStatus.Running,
+ // 定义此字段处理并发
+ LockTimeOut = 120,
});
// 将一次性任务添加到队列, 将在10(Interval)秒后被执行
From 869abc14fdedd8d2963d3e3da454d0d191828b25 Mon Sep 17 00:00:00 2001
From: cKey <35512826+colinin@users.noreply.github.com>
Date: Sat, 8 Jan 2022 23:08:44 +0800
Subject: [PATCH 03/10] fix(tasks): the execution type is job configuration
---
.../LINGYUN/Abp/BackgroundTasks/BackgroundJobManager.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 9df770d40..471a7c41a 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
@@ -44,7 +44,7 @@ public class BackgroundJobManager : IBackgroundJobManager, ITransientDependency
{
{ nameof(TArgs), args },
{ "ArgsType", jobConfiguration.ArgsType.AssemblyQualifiedName },
- { "JobType", typeof(BackgroundJobAdapter).AssemblyQualifiedName },
+ { "JobType", jobConfiguration.JobType.AssemblyQualifiedName },
};
var jobInfo = new JobInfo
{
From f307fe51ee27f5663c849a3000135fe55fc2dd64 Mon Sep 17 00:00:00 2001
From: cKey <35512826+colinin@users.noreply.github.com>
Date: Sun, 9 Jan 2022 16:20:37 +0800
Subject: [PATCH 04/10] feat(tasks): perfect management api.
---
.../LINGYUN.MicroService.TaskManagement.sln | 104 ++++++++++
.../AbpBackgroundTaskConcurrentException.cs | 45 ++++
.../Quartz/QuartzJobConcurrentAdapter.cs | 14 ++
.../Quartz/QuartzJobExecutorProvider.cs | 5 +
.../Quartz/QuartzJobListener.cs | 11 +-
.../LINGYUN.Abp.BackgroundTasks.csproj | 2 +-
.../AbpBackgroundTasksModule.cs | 2 +-
.../Internal/BackgroundCleaningJob.cs | 2 +
.../Internal/DefaultBackgroundWorker.cs | 1 +
.../Internal/JobExecutedEvent.cs | 8 +-
.../BackgroundTasks/Internal/JobLogEvent.cs | 3 +-
.../BackgroundTasks/JobRunnableExecuter.cs | 15 +-
.../BackgroundTasks/Primitives/SleepJob.cs | 16 ++
...askManagement.Application.Contracts.csproj | 1 +
.../BackgroundJobLogGetListInput.cs | 1 +
.../IBackgroundJobLogAppService.cs | 3 +-
...kManagementPermissionDefinitionProvider.cs | 60 ++++++
.../Permissions/TaskManagementPermissions.cs | 6 +
.../TaskManagementRemoteServiceConsts.cs | 8 +
.../BackgroundJobLogAppService.cs | 53 +++++
.../TaskManagementApplicationMapperProfile.cs | 1 +
.../TaskManagement/BackgroundJobInfoConsts.cs | 1 +
.../Localization/Resources/en.json | 12 +-
.../Localization/Resources/zh-Hans.json | 12 +-
.../Abp/TaskManagement/BackgroundJobInfo.cs | 29 ++-
.../Abp/TaskManagement/BackgroundJobLog.cs | 15 +-
.../TaskManagement/BackgroundJobManager.cs | 37 +++-
.../Abp/TaskManagement/BackgroundJobStore.cs | 5 +-
.../EfCoreBackgroundJobInfoRepository.cs | 2 +-
...agementDbContextModelCreatingExtensions.cs | 3 +
.../BackgroundJobInfoController.cs | 84 ++++++++
.../BackgroundJobLogController.cs | 44 ++++
.../TaskManagementController.cs | 12 ++
...916_Add-Module-Task-Management.Designer.cs | 188 +++++++++++++++++
...220109030916_Add-Module-Task-Management.cs | 108 ++++++++++
...esult-With-Background-Job-Info.Designer.cs | 193 ++++++++++++++++++
...d-Field-Result-With-Background-Job-Info.cs | 27 +++
...agementMigrationsDbContextModelSnapshot.cs | 191 +++++++++++++++++
.../TaskManagementHttpApiHostModule.cs | 8 +-
.../appsettings.Development.json | 2 +-
.../appsettings.json | 2 +-
41 files changed, 1297 insertions(+), 39 deletions(-)
create mode 100644 aspnet-core/LINGYUN.MicroService.TaskManagement.sln
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTaskConcurrentException.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobConcurrentAdapter.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/SleepJob.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/Permissions/TaskManagementPermissionDefinitionProvider.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/TaskManagementRemoteServiceConsts.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobLogAppService.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/BackgroundJobInfoController.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/BackgroundJobLogController.cs
create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/TaskManagementController.cs
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220109030916_Add-Module-Task-Management.Designer.cs
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220109030916_Add-Module-Task-Management.cs
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220109033926_Add-Field-Result-With-Background-Job-Info.Designer.cs
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220109033926_Add-Field-Result-With-Background-Job-Info.cs
create mode 100644 aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/TaskManagementMigrationsDbContextModelSnapshot.cs
diff --git a/aspnet-core/LINGYUN.MicroService.TaskManagement.sln b/aspnet-core/LINGYUN.MicroService.TaskManagement.sln
new file mode 100644
index 000000000..0ae43b0bb
--- /dev/null
+++ b/aspnet-core/LINGYUN.MicroService.TaskManagement.sln
@@ -0,0 +1,104 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "host", "host", "{8DA8A2EE-0B26-487E-A6C4-518906E92B1B}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C38EB7EF-BAE9-4129-862A-71C652B81775}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{77341F31-F54C-436A-AF8D-F78D91303C45}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.TaskManagement.Domain.Shared", "modules\task-management\LINGYUN.Abp.TaskManagement.Domain.Shared\LINGYUN.Abp.TaskManagement.Domain.Shared.csproj", "{691CD138-9FFA-4988-BAC4-A32F0DAE1090}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.TaskManagement.Domain", "modules\task-management\LINGYUN.Abp.TaskManagement.Domain\LINGYUN.Abp.TaskManagement.Domain.csproj", "{8873A651-4F83-43B3-A34E-7AAA8A3ED4CF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.TaskManagement.Application.Contracts", "modules\task-management\LINGYUN.Abp.TaskManagement.Application.Contracts\LINGYUN.Abp.TaskManagement.Application.Contracts.csproj", "{D5EC4CA0-7E16-4D17-B08E-E162EF332C77}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.TaskManagement.Application", "modules\task-management\LINGYUN.Abp.TaskManagement.Application\LINGYUN.Abp.TaskManagement.Application.csproj", "{09039DDF-5B0E-4670-8055-CC0BE82D4D2C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.TaskManagement.HttpApi", "modules\task-management\LINGYUN.Abp.TaskManagement.HttpApi\LINGYUN.Abp.TaskManagement.HttpApi.csproj", "{283B0039-F67C-41F7-B554-DF5EE9178C4A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.TaskManagement.EntityFrameworkCore", "modules\task-management\LINGYUN.Abp.TaskManagement.EntityFrameworkCore\LINGYUN.Abp.TaskManagement.EntityFrameworkCore.csproj", "{B8AB5E9B-9711-470E-8072-7444579EC5F6}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C99728F6-FB3C-4D26-8917-1D30725209B9}"
+ ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "provider", "provider", "{385578CC-C0F1-4377-A7A2-682B8F416234}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.BackgroundTasks", "modules\task-management\LINGYUN.Abp.BackgroundTasks\LINGYUN.Abp.BackgroundTasks.csproj", "{AC0B4342-9C9B-41E6-9646-E505C763EE77}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.BackgroundTasks.Quartz", "modules\task-management\LINGYUN.Abp.BackgroundTasks.Quartz\LINGYUN.Abp.BackgroundTasks.Quartz.csproj", "{7051C251-11D0-4971-B13E-F6929AE6DE89}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LY.MicroService.TaskManagement.HttpApi.Host", "services\LY.MicroService.TaskManagement.HttpApi.Host\LY.MicroService.TaskManagement.HttpApi.Host.csproj", "{E8022994-A19F-4540-B9D1-7EF4AA85D18A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.BackgroundTasks.Abstractions", "modules\task-management\LINGYUN.Abp.BackgroundTasks.Abstractions\LINGYUN.Abp.BackgroundTasks.Abstractions.csproj", "{4A049C32-55F2-4A5F-954A-C8A977C2D87F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {691CD138-9FFA-4988-BAC4-A32F0DAE1090}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {691CD138-9FFA-4988-BAC4-A32F0DAE1090}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {691CD138-9FFA-4988-BAC4-A32F0DAE1090}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {691CD138-9FFA-4988-BAC4-A32F0DAE1090}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8873A651-4F83-43B3-A34E-7AAA8A3ED4CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8873A651-4F83-43B3-A34E-7AAA8A3ED4CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8873A651-4F83-43B3-A34E-7AAA8A3ED4CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8873A651-4F83-43B3-A34E-7AAA8A3ED4CF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D5EC4CA0-7E16-4D17-B08E-E162EF332C77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D5EC4CA0-7E16-4D17-B08E-E162EF332C77}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D5EC4CA0-7E16-4D17-B08E-E162EF332C77}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D5EC4CA0-7E16-4D17-B08E-E162EF332C77}.Release|Any CPU.Build.0 = Release|Any CPU
+ {09039DDF-5B0E-4670-8055-CC0BE82D4D2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {09039DDF-5B0E-4670-8055-CC0BE82D4D2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {09039DDF-5B0E-4670-8055-CC0BE82D4D2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {09039DDF-5B0E-4670-8055-CC0BE82D4D2C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {283B0039-F67C-41F7-B554-DF5EE9178C4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {283B0039-F67C-41F7-B554-DF5EE9178C4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {283B0039-F67C-41F7-B554-DF5EE9178C4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {283B0039-F67C-41F7-B554-DF5EE9178C4A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B8AB5E9B-9711-470E-8072-7444579EC5F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B8AB5E9B-9711-470E-8072-7444579EC5F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B8AB5E9B-9711-470E-8072-7444579EC5F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B8AB5E9B-9711-470E-8072-7444579EC5F6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AC0B4342-9C9B-41E6-9646-E505C763EE77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AC0B4342-9C9B-41E6-9646-E505C763EE77}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AC0B4342-9C9B-41E6-9646-E505C763EE77}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AC0B4342-9C9B-41E6-9646-E505C763EE77}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7051C251-11D0-4971-B13E-F6929AE6DE89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7051C251-11D0-4971-B13E-F6929AE6DE89}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7051C251-11D0-4971-B13E-F6929AE6DE89}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7051C251-11D0-4971-B13E-F6929AE6DE89}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E8022994-A19F-4540-B9D1-7EF4AA85D18A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E8022994-A19F-4540-B9D1-7EF4AA85D18A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E8022994-A19F-4540-B9D1-7EF4AA85D18A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E8022994-A19F-4540-B9D1-7EF4AA85D18A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4A049C32-55F2-4A5F-954A-C8A977C2D87F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4A049C32-55F2-4A5F-954A-C8A977C2D87F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4A049C32-55F2-4A5F-954A-C8A977C2D87F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4A049C32-55F2-4A5F-954A-C8A977C2D87F}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {691CD138-9FFA-4988-BAC4-A32F0DAE1090} = {C38EB7EF-BAE9-4129-862A-71C652B81775}
+ {8873A651-4F83-43B3-A34E-7AAA8A3ED4CF} = {C38EB7EF-BAE9-4129-862A-71C652B81775}
+ {D5EC4CA0-7E16-4D17-B08E-E162EF332C77} = {C38EB7EF-BAE9-4129-862A-71C652B81775}
+ {09039DDF-5B0E-4670-8055-CC0BE82D4D2C} = {C38EB7EF-BAE9-4129-862A-71C652B81775}
+ {283B0039-F67C-41F7-B554-DF5EE9178C4A} = {C38EB7EF-BAE9-4129-862A-71C652B81775}
+ {B8AB5E9B-9711-470E-8072-7444579EC5F6} = {C38EB7EF-BAE9-4129-862A-71C652B81775}
+ {AC0B4342-9C9B-41E6-9646-E505C763EE77} = {C38EB7EF-BAE9-4129-862A-71C652B81775}
+ {7051C251-11D0-4971-B13E-F6929AE6DE89} = {385578CC-C0F1-4377-A7A2-682B8F416234}
+ {E8022994-A19F-4540-B9D1-7EF4AA85D18A} = {8DA8A2EE-0B26-487E-A6C4-518906E92B1B}
+ {4A049C32-55F2-4A5F-954A-C8A977C2D87F} = {C38EB7EF-BAE9-4129-862A-71C652B81775}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {E1FD1F4C-D344-408B-97CF-B6F1F6D7D293}
+ EndGlobalSection
+EndGlobal
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTaskConcurrentException.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTaskConcurrentException.cs
new file mode 100644
index 000000000..a4f65d170
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTaskConcurrentException.cs
@@ -0,0 +1,45 @@
+using System;
+using Volo.Abp;
+
+namespace LINGYUN.Abp.BackgroundTasks;
+
+public class AbpBackgroundTaskConcurrentException : AbpException
+{
+ public Type JobType { get; }
+ ///
+ /// Creates a new object.
+ ///
+ /// Inner exception
+ public AbpBackgroundTaskConcurrentException(Type jobType)
+ : this(
+ jobType,
+ $"This job {jobType.Name} cannot be performed because it has been locked by another performer",
+ null)
+ {
+ }
+
+ ///
+ /// Creates a new object.
+ ///
+ /// Execute job type
+ /// Inner exception
+ public AbpBackgroundTaskConcurrentException(Type jobType, Exception innerException)
+ : this(
+ jobType,
+ $"This job {jobType.Name} cannot be performed because it has been locked by another performer",
+ innerException)
+ {
+ }
+
+ ///
+ /// Creates a new object.
+ ///
+ /// Execute job type
+ /// Exception message
+ /// Inner exception
+ public AbpBackgroundTaskConcurrentException(Type jobType, string message, Exception innerException)
+ : base(message, innerException)
+ {
+ JobType = jobType;
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobConcurrentAdapter.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobConcurrentAdapter.cs
new file mode 100644
index 000000000..1fde4e3c0
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobConcurrentAdapter.cs
@@ -0,0 +1,14 @@
+using System;
+using Quartz;
+
+namespace LINGYUN.Abp.BackgroundTasks.Quartz;
+
+[DisallowConcurrentExecution]
+public class QuartzJobConcurrentAdapter : QuartzJobSimpleAdapter
+ where TJobRunnable : IJobRunnable
+{
+ public QuartzJobConcurrentAdapter(IServiceProvider serviceProvider)
+ : base(serviceProvider)
+ {
+ }
+}
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 ec3ab3501..45f35155e 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
@@ -35,6 +35,10 @@ public class QuartzJobExecutorProvider : IQuartzJobExecutorProvider, ISingletonD
}
var adapterType = typeof(QuartzJobSimpleAdapter<>);
+ if (job.LockTimeOut > 0)
+ {
+ adapterType = typeof(QuartzJobConcurrentAdapter<>);
+ }
if (!typeof(IJob).IsAssignableFrom(jobType))
{
@@ -88,6 +92,7 @@ public class QuartzJobExecutorProvider : IQuartzJobExecutorProvider, ISingletonD
triggerBuilder
.WithIdentity(job.Name, job.Group)
.WithDescription(job.Description)
+ .StartAt(Clock.Now.AddSeconds(job.Interval))
.EndAt(job.EndTime)
.ForJob(job.Name, job.Group)
.WithPriority((int)job.Priority)
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobListener.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobListener.cs
index 7408ffcf2..b90cb54b6 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobListener.cs
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobListener.cs
@@ -82,7 +82,6 @@ public class QuartzJobListener : JobListenerSupport, ISingletonDependency
}
}
- [UnitOfWork]
public override async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default)
{
try
@@ -91,9 +90,15 @@ public class QuartzJobListener : JobListenerSupport, ISingletonDependency
var jobId = context.GetString(nameof(JobInfo.Id));
if (Guid.TryParse(jobId, out var jobUUId))
{
+ var jobType = context.JobDetail.JobType;
+ if (jobType.IsGenericType)
+ {
+ jobType = jobType.GetGenericArguments()[0];
+ }
+
var jobEventData = new JobEventData(
jobUUId,
- context.JobDetail.JobType,
+ jobType,
context.JobDetail.Key.Group,
context.JobDetail.Key.Name,
jobException)
@@ -112,7 +117,7 @@ public class QuartzJobListener : JobListenerSupport, ISingletonDependency
jobEventData.NextRunTime = context.NextFireTimeUtc?.LocalDateTime;
if (context.Result != null)
{
- jobEventData.Result = context.Result.ToString();
+ jobEventData.Result = context.Result?.ToString();
}
var tenantIdString = context.GetString(nameof(IMultiTenant.TenantId));
if (Guid.TryParse(tenantIdString, out var tenantId))
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN.Abp.BackgroundTasks.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN.Abp.BackgroundTasks.csproj
index 96b629b02..14206d3f2 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN.Abp.BackgroundTasks.csproj
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN.Abp.BackgroundTasks.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksModule.cs
index 205ccd0e9..2ee46ed95 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksModule.cs
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksModule.cs
@@ -12,9 +12,9 @@ using Volo.Abp.Reflection;
namespace LINGYUN.Abp.BackgroundTasks;
[DependsOn(typeof(AbpAuditingModule))]
-[DependsOn(typeof(AbpDistributedLockingModule))]
[DependsOn(typeof(AbpBackgroundTasksAbstractionsModule))]
[DependsOn(typeof(AbpBackgroundJobsAbstractionsModule))]
+[DependsOn(typeof(AbpDistributedLockingAbstractionsModule))]
[DependsOn(typeof(AbpGuidsModule))]
public class AbpBackgroundTasksModule : AbpModule
{
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 ee767808d..f21537b5d 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
@@ -1,9 +1,11 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
+using Volo.Abp.Auditing;
namespace LINGYUN.Abp.BackgroundTasks.Internal;
+[DisableAuditing]
internal class BackgroundCleaningJob : IJobRunnable
{
public virtual async Task ExecuteAsync(JobRunnableContext context)
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 e86ae7879..adce084cb 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
@@ -63,6 +63,7 @@ internal class DefaultBackgroundWorker : BackgroundService
JobType = JobType.Once,
Priority = JobPriority.High,
MaxCount = 1,
+ Interval = 30,
Type = typeof(BackgroundKeepAliveJob).AssemblyQualifiedName,
};
}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobExecutedEvent.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobExecutedEvent.cs
index 4cbbc0fd9..dd2275dde 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobExecutedEvent.cs
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobExecutedEvent.cs
@@ -4,7 +4,7 @@ using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.BackgroundTasks.Internal;
-internal class JobExecutedEvent : JobEventBase, ITransientDependency
+public class JobExecutedEvent : JobEventBase, ITransientDependency
{
protected override async Task OnJobAfterExecutedAsync(JobEventContext context)
{
@@ -15,8 +15,8 @@ internal class JobExecutedEvent : JobEventBase, ITransientDepe
{
job.TriggerCount += 1;
job.NextRunTime = context.EventData.NextRunTime;
- job.LastRunTime = context.EventData.LastRunTime;
- job.Result = context.EventData.Result;
+ job.LastRunTime = context.EventData.RunTime;
+ job.Result = context.EventData.Result ?? "OK";
// 一次性任务执行一次后标记为已完成
if (job.JobType == JobType.Once)
@@ -53,7 +53,7 @@ internal class JobExecutedEvent : JobEventBase, ITransientDepe
}
// 所有任务达到上限则标记已完成
- if (job.MaxCount > 0 && job.TriggerCount > job.MaxCount)
+ if (job.MaxCount > 0 && job.TriggerCount >= job.MaxCount)
{
job.Status = JobStatus.Completed;
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobLogEvent.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobLogEvent.cs
index 6fb015762..8a239d806 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobLogEvent.cs
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobLogEvent.cs
@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
+using Volo.Abp.Uow;
namespace LINGYUN.Abp.BackgroundTasks.Internal;
@@ -11,7 +12,7 @@ namespace LINGYUN.Abp.BackgroundTasks.Internal;
///
/// 任务类型标记了 特性则不会记录日志
///
-internal class JobLogEvent : JobEventBase, ITransientDependency
+public class JobLogEvent : JobEventBase, ITransientDependency
{
protected async override Task OnJobAfterExecutedAsync(JobEventContext context)
{
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobRunnableExecuter.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobRunnableExecuter.cs
index 24ad6721f..042f681fa 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobRunnableExecuter.cs
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/JobRunnableExecuter.cs
@@ -10,7 +10,7 @@ namespace LINGYUN.Abp.BackgroundTasks;
public class JobRunnableExecuter : IJobRunnableExecuter, ISingletonDependency
{
- protected const string LockKeyFormat = "job:{0},key:{1}";
+ protected const string LockKeyFormat = "p:{0},job:{1},key:{2}";
public async virtual Task ExecuteAsync(JobRunnableContext context)
{
@@ -26,12 +26,21 @@ public class JobRunnableExecuter : IJobRunnableExecuter, ISingletonDependency
{
context.JobData.TryGetValue(nameof(JobInfo.LockTimeOut), out var lockTime);
+ // 某些提供者如果无法保证锁一致性, 那么需要用分布式锁
if (lockTime != null && (lockTime is int time && time > 0))
{
var jobId = context.JobData.GetOrDefault(nameof(JobInfo.Id));
- var jobLockKey = string.Format(LockKeyFormat, context.JobType.Name, jobId);
+ var jobLockKey = string.Format(LockKeyFormat, tenantId?.ToString() ?? "Default", context.JobType.Name, jobId);
var distributedLock = context.ServiceProvider.GetRequiredService();
- await using (await distributedLock.TryAcquireAsync(jobLockKey, TimeSpan.FromSeconds(time)))
+
+ var handle = await distributedLock.TryAcquireAsync(jobLockKey, TimeSpan.FromSeconds(time));
+ if (handle == null)
+ {
+ // 抛出异常 通过监听器使其重试
+ throw new AbpBackgroundTaskConcurrentException(context.JobType);
+ }
+
+ await using (handle)
{
await InternalExecuteAsync(context);
}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/SleepJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/SleepJob.cs
new file mode 100644
index 000000000..d2f65f17e
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Primitives/SleepJob.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.BackgroundTasks.Primitives;
+
+public class SleepJob : IJobRunnable
+{
+ public async Task ExecuteAsync(JobRunnableContext context)
+ {
+ context.JobData.TryGetValue("Delay", out var sleep);
+
+ Console.WriteLine($"Sleep {sleep ?? 20000} milliseconds.");
+
+ await Task.Delay(sleep?.To() ?? 20000);
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN.Abp.TaskManagement.Application.Contracts.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN.Abp.TaskManagement.Application.Contracts.csproj
index d7b51dbfa..19dfce08a 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN.Abp.TaskManagement.Application.Contracts.csproj
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN.Abp.TaskManagement.Application.Contracts.csproj
@@ -9,6 +9,7 @@
+
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobLogGetListInput.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobLogGetListInput.cs
index 2967be0aa..2c8ee69c9 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobLogGetListInput.cs
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/BackgroundJobLogGetListInput.cs
@@ -5,6 +5,7 @@ namespace LINGYUN.Abp.TaskManagement;
public class BackgroundJobLogGetListInput : PagedAndSortedResultRequestDto
{
+ public Guid? JobId { get; set; }
///
/// 其他过滤条件
///
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/IBackgroundJobLogAppService.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/IBackgroundJobLogAppService.cs
index cc41aae14..6acde52ff 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/IBackgroundJobLogAppService.cs
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/IBackgroundJobLogAppService.cs
@@ -6,6 +6,7 @@ public interface IBackgroundJobLogAppService :
IReadOnlyAppService<
BackgroundJobLogDto,
long,
- BackgroundJobLogGetListInput>
+ BackgroundJobLogGetListInput>,
+ IDeleteAppService
{
}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/Permissions/TaskManagementPermissionDefinitionProvider.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/Permissions/TaskManagementPermissionDefinitionProvider.cs
new file mode 100644
index 000000000..34503780c
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/Permissions/TaskManagementPermissionDefinitionProvider.cs
@@ -0,0 +1,60 @@
+using LINGYUN.Abp.TaskManagement.Localization;
+using Volo.Abp.Authorization.Permissions;
+using Volo.Abp.Localization;
+using Volo.Abp.MultiTenancy;
+
+namespace LINGYUN.Abp.TaskManagement.Permissions;
+
+public class TaskManagementPermissionDefinitionProvider : PermissionDefinitionProvider
+{
+ public override void Define(IPermissionDefinitionContext context)
+ {
+ var group = context.AddGroup(
+ TaskManagementPermissions.GroupName,
+ L("Permissions:TaskManagement"),
+ MultiTenancySides.Host);
+
+ var backgroundJobs = group.AddPermission(
+ TaskManagementPermissions.BackgroundJobs.Default,
+ L("Permissions:BackgroundJobs"),
+ MultiTenancySides.Host);
+ backgroundJobs.AddChild(
+ TaskManagementPermissions.BackgroundJobs.Create,
+ L("Permissions:CreateJob"),
+ MultiTenancySides.Host);
+ backgroundJobs.AddChild(
+ TaskManagementPermissions.BackgroundJobs.Update,
+ L("Permissions:UpdateJob"),
+ MultiTenancySides.Host);
+ backgroundJobs.AddChild(
+ TaskManagementPermissions.BackgroundJobs.Delete,
+ L("Permissions:DeleteJob"),
+ MultiTenancySides.Host);
+ backgroundJobs.AddChild(
+ TaskManagementPermissions.BackgroundJobs.Trigger,
+ L("Permissions:TriggerJob"),
+ MultiTenancySides.Host);
+ backgroundJobs.AddChild(
+ TaskManagementPermissions.BackgroundJobs.Pause,
+ L("Permissions:PauseJob"),
+ MultiTenancySides.Host);
+ backgroundJobs.AddChild(
+ TaskManagementPermissions.BackgroundJobs.Resume,
+ L("Permissions:ResumeJob"),
+ MultiTenancySides.Host);
+
+ var backgroundJobLogs = group.AddPermission(
+ TaskManagementPermissions.BackgroundJobLogs.Default,
+ L("Permissions:BackgroundJobLogs"),
+ MultiTenancySides.Host);
+ backgroundJobLogs.AddChild(
+ TaskManagementPermissions.BackgroundJobLogs.Delete,
+ L("Permissions:DeleteJobLogs"),
+ MultiTenancySides.Host);
+ }
+
+ private ILocalizableString L(string name)
+ {
+ return LocalizableString.Create(name);
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/Permissions/TaskManagementPermissions.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/Permissions/TaskManagementPermissions.cs
index 8ca7655fe..b30f69d67 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/Permissions/TaskManagementPermissions.cs
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/Permissions/TaskManagementPermissions.cs
@@ -14,4 +14,10 @@ public static class TaskManagementPermissions
public const string Pause = Default + ".Pause";
public const string Resume = Default + ".Resume";
}
+
+ public static class BackgroundJobLogs
+ {
+ public const string Default = GroupName + ".BackgroundJobLogs";
+ public const string Delete = Default + ".Delete";
+ }
}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/TaskManagementRemoteServiceConsts.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/TaskManagementRemoteServiceConsts.cs
new file mode 100644
index 000000000..c2d6dccd2
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN/Abp/TaskManagement/TaskManagementRemoteServiceConsts.cs
@@ -0,0 +1,8 @@
+namespace LINGYUN.Abp.TaskManagement;
+
+public static class TaskManagementRemoteServiceConsts
+{
+ public const string RemoteServiceName = "TaskManagement";
+
+ public const string ModuleName = "task-management";
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobLogAppService.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobLogAppService.cs
new file mode 100644
index 000000000..012a1db32
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobLogAppService.cs
@@ -0,0 +1,53 @@
+using LINGYUN.Abp.TaskManagement.Permissions;
+using Microsoft.AspNetCore.Authorization;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp.Application.Dtos;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+[Authorize(TaskManagementPermissions.BackgroundJobLogs.Default)]
+public class BackgroundJobLogAppService : TaskManagementApplicationService, IBackgroundJobLogAppService
+{
+ protected IBackgroundJobLogRepository BackgroundJobLogRepository { get; }
+
+ public BackgroundJobLogAppService(
+ IBackgroundJobLogRepository backgroundJobLogRepository)
+ {
+ BackgroundJobLogRepository = backgroundJobLogRepository;
+ }
+
+ [Authorize(TaskManagementPermissions.BackgroundJobLogs.Delete)]
+ public virtual Task DeleteAsync(long id)
+ {
+ return BackgroundJobLogRepository.DeleteAsync(id);
+ }
+
+ public virtual async Task GetAsync(long id)
+ {
+ var backgroundJobLog = await BackgroundJobLogRepository.GetAsync(id);
+
+ return ObjectMapper.Map(backgroundJobLog);
+ }
+
+ public virtual async Task> GetListAsync(BackgroundJobLogGetListInput input)
+ {
+ var filter = new BackgroundJobLogFilter
+ {
+ BeginRunTime = input.BeginRunTime,
+ EndRunTime = input.EndRunTime,
+ HasExceptions = input.HasExceptions,
+ Filter = input.Filter,
+ Group = input.Group,
+ Name = input.Name,
+ Type = input.Type
+ };
+
+ var totalCount = await BackgroundJobLogRepository.GetCountAsync(filter, input.JobId);
+ var backgroundJobLogs = await BackgroundJobLogRepository.GetListAsync(
+ filter, input.JobId, input.Sorting, input.MaxResultCount, input.SkipCount);
+
+ return new PagedResultDto(totalCount,
+ ObjectMapper.Map, List>(backgroundJobLogs));
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationMapperProfile.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationMapperProfile.cs
index 11468eb23..f250cfe5a 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationMapperProfile.cs
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/TaskManagementApplicationMapperProfile.cs
@@ -7,5 +7,6 @@ public class TaskManagementApplicationMapperProfile : Profile
public TaskManagementApplicationMapperProfile()
{
CreateMap();
+ CreateMap();
}
}
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 bc316921f..25c26d24c 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
@@ -7,4 +7,5 @@ public static class BackgroundJobInfoConsts
public static int MaxGroupLength { get; set; } = 50;
public static int MaxTypeLength { get; set; } = 200;
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.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/en.json b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/en.json
index 10f2dda00..6f45cd09e 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/en.json
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/en.json
@@ -1,6 +1,16 @@
{
"culture": "en",
"texts": {
- "Permission:TaskManagement": "TaskManagement"
+ "Permissions:TaskManagement": "Task Management",
+ "Permissions:BackgroundJobs": "Background Jobs",
+ "Permissions:CreateJob": "Create Job",
+ "Permissions:UpdateJob": "Update Job",
+ "Permissions:DeleteJob": "Delete Job",
+ "Permissions:TriggerJob": "Trigger Job",
+ "Permissions:PauseJob": "Pause Job",
+ "Permissions:ResumeJob": "Resume Job",
+ "Permissions:BackgroundJobLogs": "BackgroundJobs Logs",
+ "Permissions:DeleteJobLogs": "Delete Job Logs",
+ "TaskManagement:01000": "A job named {Name} already exists in the Group {Group}!"
}
}
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/zh-Hans.json b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/zh-Hans.json
index 5b3611e36..02a7e286b 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/zh-Hans.json
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/zh-Hans.json
@@ -1,6 +1,16 @@
{
"culture": "zh-Hans",
"texts": {
- "Permission:TaskManagement": "任务管理"
+ "Permissions:TaskManagement": "任务调度平台",
+ "Permissions:BackgroundJobs": "任务管理",
+ "Permissions:CreateJob": "新建作业",
+ "Permissions:UpdateJob": "编辑作业",
+ "Permissions:DeleteJob": "删除作业",
+ "Permissions:TriggerJob": "触发作业",
+ "Permissions:PauseJob": "暂停作业",
+ "Permissions:ResumeJob": "恢复作业",
+ "Permissions:BackgroundJobLogs": "日志管理",
+ "Permissions:DeleteJobLogs": "删除作业日志",
+ "TaskManagement:01000": "分组 {Group} 中已经存在一个名称为 {Name} 的作业!"
}
}
\ No newline at end of file
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 4704f65b9..bb3d5d1e7 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
@@ -1,6 +1,7 @@
using LINGYUN.Abp.BackgroundTasks;
using System;
using System.Collections.Generic;
+using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities.Auditing;
@@ -21,6 +22,10 @@ public class BackgroundJobInfo : AuditedAggregateRoot
///
public virtual string Type { get; protected set; }
///
+ /// 上一次执行结果
+ ///
+ public virtual string Result { get; protected set; }
+ ///
/// 任务参数
///
public virtual ExtraPropertyDictionary Args { get; protected set; }
@@ -111,9 +116,9 @@ public class BackgroundJobInfo : AuditedAggregateRoot
int maxCount = 0,
int maxTryCount = 50) : base(id)
{
- Name = name;
- Group = group;
- Type = type;
+ Name = Check.NotNullOrWhiteSpace(name, nameof(name), BackgroundJobInfoConsts.MaxNameLength);
+ Group = Check.NotNullOrWhiteSpace(group, nameof(group), BackgroundJobInfoConsts.MaxGroupLength);
+ Type = Check.NotNullOrWhiteSpace(type, nameof(type), BackgroundJobInfoConsts.MaxTypeLength);
Priority = priority;
BeginTime = beginTime;
EndTime = endTime;
@@ -123,13 +128,15 @@ public class BackgroundJobInfo : AuditedAggregateRoot
Status = JobStatus.Running;
+ // TODO: 是否需要将参数挪到另一个实体?
+ // 任务参数的建议是尽量最小化, 仅存储关键信息
Args = new ExtraPropertyDictionary();
Args.AddIfNotContains(args);
}
public void SetPeriodJob(string cron)
{
- Cron = cron;
+ Cron = Check.NotNullOrWhiteSpace(cron, nameof(cron), BackgroundJobInfoConsts.MaxCronLength);
JobType = JobType.Period;
}
@@ -155,6 +162,20 @@ public class BackgroundJobInfo : AuditedAggregateRoot
NextRunTime = nextRunTime;
}
+ public void SetResult(string result)
+ {
+ if (result.IsNullOrWhiteSpace())
+ {
+ return;
+ }
+ if (result.Length > BackgroundJobInfoConsts.MaxResultLength)
+ {
+ result = result.Substring(0, BackgroundJobInfoConsts.MaxResultLength - 1);
+ }
+
+ Result = result;
+ }
+
public void SetStatus(JobStatus status)
{
Status = status;
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLog.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLog.cs
index 9ae5ca1d0..192eaaacb 100644
--- a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLog.cs
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLog.cs
@@ -1,4 +1,5 @@
using System;
+using Volo.Abp;
using Volo.Abp.Domain.Entities;
namespace LINGYUN.Abp.TaskManagement;
@@ -13,12 +14,16 @@ public class BackgroundJobLog : Entity
public virtual DateTime RunTime { get; protected set; }
public virtual string Exception { get; protected set; }
protected BackgroundJobLog() { }
- public BackgroundJobLog(string type, string group, string name)
+ public BackgroundJobLog(
+ string type,
+ string group,
+ string name,
+ DateTime runTime)
{
- JobType = type;
- JobGroup = group;
- JobName = name;
- RunTime = DateTime.Now;
+ JobType = Check.NotNullOrWhiteSpace(type, nameof(type), BackgroundJobInfoConsts.MaxTypeLength);
+ JobGroup = Check.NotNullOrWhiteSpace(group, nameof(group), BackgroundJobInfoConsts.MaxGroupLength);
+ JobName = Check.NotNullOrWhiteSpace(name, nameof(name), BackgroundJobInfoConsts.MaxNameLength);
+ RunTime = runTime;
}
public BackgroundJobLog SetMessage(string message, Exception ex)
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 06b39aaea..bf7d50bd1 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,9 @@
using LINGYUN.Abp.BackgroundTasks;
using System.Threading.Tasks;
+using Volo.Abp;
using Volo.Abp.Domain.Services;
using Volo.Abp.ObjectMapping;
+using Volo.Abp.Uow;
namespace LINGYUN.Abp.TaskManagement;
@@ -9,15 +11,18 @@ public class BackgroundJobManager : DomainService
{
protected IObjectMapper ObjectMapper { get; }
protected IJobScheduler JobScheduler { get; }
+ protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected IBackgroundJobInfoRepository BackgroundJobInfoRepository { get; }
public BackgroundJobManager(
IObjectMapper objectMapper,
IJobScheduler jobScheduler,
+ IUnitOfWorkManager unitOfWorkManager,
IBackgroundJobInfoRepository backgroundJobInfoRepository)
{
ObjectMapper = objectMapper;
JobScheduler = jobScheduler;
+ UnitOfWorkManager = unitOfWorkManager;
BackgroundJobInfoRepository = backgroundJobInfoRepository;
}
@@ -28,7 +33,16 @@ public class BackgroundJobManager : DomainService
if (jobInfo.IsEnabled && jobInfo.JobType == JobType.Period)
{
var job = ObjectMapper.Map(jobInfo);
- await JobScheduler.QueueAsync(job);
+ 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);
+ });
}
return jobInfo;
@@ -40,13 +54,19 @@ public class BackgroundJobManager : DomainService
if (!jobInfo.IsEnabled || resetJob)
{
- var job = ObjectMapper.Map(jobInfo);
- await JobScheduler.RemoveAsync(job);
+ UnitOfWorkManager.Current.OnCompleted(async () =>
+ {
+ var job = ObjectMapper.Map(jobInfo);
+ await JobScheduler.RemoveAsync(job);
+ });
}
if (resetJob && jobInfo.JobType == JobType.Period)
{
- await QueueAsync(jobInfo);
+ UnitOfWorkManager.Current.OnCompleted(async () =>
+ {
+ await QueueAsync(jobInfo);
+ });
}
return jobInfo;
@@ -54,10 +74,13 @@ public class BackgroundJobManager : DomainService
public virtual async Task DeleteAsync(BackgroundJobInfo jobInfo)
{
- var job = ObjectMapper.Map(jobInfo);
- await JobScheduler.RemoveAsync(job);
-
await BackgroundJobInfoRepository.DeleteAsync(jobInfo);
+
+ UnitOfWorkManager.Current.OnCompleted(async () =>
+ {
+ var job = ObjectMapper.Map(jobInfo);
+ await JobScheduler.RemoveAsync(job);
+ });
}
public virtual async Task QueueAsync(BackgroundJobInfo jobInfo)
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 e5498ab6f..189f0bf9c 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
@@ -56,6 +56,7 @@ public class BackgroundJobStore : IJobStore, ITransientDependency
backgroundJobInfo.SetNextRunTime(jobInfo.NextRunTime);
backgroundJobInfo.SetLastRunTime(jobInfo.LastRunTime);
backgroundJobInfo.SetStatus(jobInfo.Status);
+ backgroundJobInfo.SetResult(jobInfo.Result);
backgroundJobInfo.TriggerCount = jobInfo.TriggerCount;
backgroundJobInfo.TryCount = jobInfo.TryCount;
backgroundJobInfo.IsAbandoned = jobInfo.IsAbandoned;
@@ -79,6 +80,7 @@ public class BackgroundJobStore : IJobStore, ITransientDependency
backgroundJobInfo.SetNextRunTime(jobInfo.NextRunTime);
backgroundJobInfo.SetLastRunTime(jobInfo.LastRunTime);
backgroundJobInfo.SetStatus(jobInfo.Status);
+ backgroundJobInfo.SetResult(jobInfo.Result);
backgroundJobInfo.TriggerCount = jobInfo.TriggerCount;
backgroundJobInfo.IsAbandoned = jobInfo.IsAbandoned;
backgroundJobInfo.TryCount = jobInfo.TryCount;
@@ -107,7 +109,8 @@ public class BackgroundJobStore : IJobStore, ITransientDependency
var jogLog = new BackgroundJobLog(
eventData.Type.Name,
eventData.Group,
- eventData.Name)
+ eventData.Name,
+ eventData.RunTime)
{
JobId = eventData.Key
};
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 8cc7bc601..ff840e35c 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
@@ -32,7 +32,7 @@ public class EfCoreBackgroundJobInfoRepository :
CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
- .AllAsync(x => x.Group.Equals(group) && x.Name.Equals(name),
+ .AnyAsync(x => x.Group.Equals(group) && x.Name.Equals(name),
GetCancellationToken(cancellationToken));
}
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 c32fabef7..e85773fb2 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
@@ -43,6 +43,9 @@ public static class TaskManagementDbContextModelCreatingExtensions
b.Property(p => p.Description)
.HasColumnName(nameof(BackgroundJobInfo.Description))
.HasMaxLength(BackgroundJobInfoConsts.MaxDescriptionLength);
+ b.Property(p => p.Result)
+ .HasColumnName(nameof(BackgroundJobInfo.Result))
+ .HasMaxLength(BackgroundJobInfoConsts.MaxResultLength);
b.Property(p => p.Args)
.HasColumnName(nameof(BackgroundJobInfo.Args))
.HasConversion(new ExtraPropertiesValueConverter(b.Metadata.ClrType))
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/BackgroundJobInfoController.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/BackgroundJobInfoController.cs
new file mode 100644
index 000000000..dd755ebbd
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/BackgroundJobInfoController.cs
@@ -0,0 +1,84 @@
+using LINGYUN.Abp.TaskManagement.Permissions;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Application.Dtos;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+[RemoteService(Name = TaskManagementRemoteServiceConsts.RemoteServiceName)]
+[Area(TaskManagementRemoteServiceConsts.ModuleName)]
+[Authorize(TaskManagementPermissions.BackgroundJobs.Default)]
+[Route($"api/{TaskManagementRemoteServiceConsts.ModuleName}/background-jobs")]
+public class BackgroundJobInfoController : TaskManagementController, IBackgroundJobInfoAppService
+{
+ protected IBackgroundJobInfoAppService BackgroundJobInfoAppService { get; }
+
+ public BackgroundJobInfoController(
+ IBackgroundJobInfoAppService backgroundJobInfoAppService)
+ {
+ BackgroundJobInfoAppService = backgroundJobInfoAppService;
+ }
+
+ [HttpPost]
+ [Authorize(TaskManagementPermissions.BackgroundJobs.Create)]
+ public Task CreateAsync(BackgroundJobInfoCreateDto input)
+ {
+ return BackgroundJobInfoAppService.CreateAsync(input);
+ }
+
+ [HttpDelete]
+ [Route("{id}")]
+ [Authorize(TaskManagementPermissions.BackgroundJobs.Delete)]
+ public Task DeleteAsync(Guid id)
+ {
+ return BackgroundJobInfoAppService.DeleteAsync(id);
+ }
+
+ [HttpGet]
+ [Route("{id}")]
+ public Task GetAsync(Guid id)
+ {
+ return BackgroundJobInfoAppService.GetAsync(id);
+ }
+
+ [HttpGet]
+ public Task> GetListAsync(BackgroundJobInfoGetListInput input)
+ {
+ return BackgroundJobInfoAppService.GetListAsync(input);
+ }
+
+ [HttpPut]
+ [Route("{id}/pause")]
+ [Authorize(TaskManagementPermissions.BackgroundJobs.Pause)]
+ public Task PauseAsync(Guid id)
+ {
+ return BackgroundJobInfoAppService.PauseAsync(id);
+ }
+
+ [HttpPut]
+ [Route("{id}/resume")]
+ [Authorize(TaskManagementPermissions.BackgroundJobs.Resume)]
+ public Task ResumeAsync(Guid id)
+ {
+ return BackgroundJobInfoAppService.ResumeAsync(id);
+ }
+
+ [HttpPut]
+ [Route("{id}/trigger")]
+ [Authorize(TaskManagementPermissions.BackgroundJobs.Trigger)]
+ public Task TriggerAsync(Guid id)
+ {
+ return BackgroundJobInfoAppService.TriggerAsync(id);
+ }
+
+ [HttpPut]
+ [Route("{id}")]
+ [Authorize(TaskManagementPermissions.BackgroundJobs.Update)]
+ public Task UpdateAsync(Guid id, BackgroundJobInfoUpdateDto input)
+ {
+ return BackgroundJobInfoAppService.UpdateAsync(id, input);
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/BackgroundJobLogController.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/BackgroundJobLogController.cs
new file mode 100644
index 000000000..a84ddb52a
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/BackgroundJobLogController.cs
@@ -0,0 +1,44 @@
+using LINGYUN.Abp.TaskManagement.Permissions;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Application.Dtos;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+[RemoteService(Name = TaskManagementRemoteServiceConsts.RemoteServiceName)]
+[Area(TaskManagementRemoteServiceConsts.ModuleName)]
+[Authorize(TaskManagementPermissions.BackgroundJobLogs.Default)]
+[Route($"api/{TaskManagementRemoteServiceConsts.ModuleName}/background-jobs/logs")]
+public class BackgroundJobLogController : TaskManagementController, IBackgroundJobLogAppService
+{
+ protected IBackgroundJobLogAppService BackgroundJobLogAppService { get; }
+
+ public BackgroundJobLogController(
+ IBackgroundJobLogAppService backgroundJobLogAppService)
+ {
+ BackgroundJobLogAppService = backgroundJobLogAppService;
+ }
+
+ [HttpDelete]
+ [Route("{id}")]
+ [Authorize(TaskManagementPermissions.BackgroundJobLogs.Delete)]
+ public Task DeleteAsync(long id)
+ {
+ return BackgroundJobLogAppService.DeleteAsync(id);
+ }
+
+ [HttpGet]
+ [Route("{id}")]
+ public Task GetAsync(long id)
+ {
+ return BackgroundJobLogAppService.GetAsync(id);
+ }
+
+ [HttpGet]
+ public Task> GetListAsync(BackgroundJobLogGetListInput input)
+ {
+ return BackgroundJobLogAppService.GetListAsync(input);
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/TaskManagementController.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/TaskManagementController.cs
new file mode 100644
index 000000000..0e011fd88
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.HttpApi/LINGYUN/Abp/TaskManagement/TaskManagementController.cs
@@ -0,0 +1,12 @@
+using LINGYUN.Abp.TaskManagement.Localization;
+using Volo.Abp.AspNetCore.Mvc;
+
+namespace LINGYUN.Abp.TaskManagement;
+
+public abstract class TaskManagementController : AbpControllerBase
+{
+ protected TaskManagementController()
+ {
+ LocalizationResource = typeof(TaskManagementResource);
+ }
+}
diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220109030916_Add-Module-Task-Management.Designer.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220109030916_Add-Module-Task-Management.Designer.cs
new file mode 100644
index 000000000..bb69b999d
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220109030916_Add-Module-Task-Management.Designer.cs
@@ -0,0 +1,188 @@
+//
+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("20220109030916_Add-Module-Task-Management")]
+ partial class AddModuleTaskManagement
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql)
+ .HasAnnotation("ProductVersion", "6.0.1")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ modelBuilder.Entity("LINGYUN.Abp.TaskManagement.BackgroundJobInfo", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)");
+
+ 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("Priority")
+ .HasColumnType("int");
+
+ b.Property("Status")
+ .HasColumnType("int");
+
+ b.Property("TriggerCount")
+ .HasColumnType("int");
+
+ b.Property("TryCount")
+ .HasColumnType("int");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .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")
+ .HasColumnType("char(36)");
+
+ b.Property("JobName")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)")
+ .HasColumnName("JobName");
+
+ b.Property("JobType")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnName("JobType");
+
+ b.Property("Message")
+ .HasMaxLength(1000)
+ .HasColumnType("varchar(1000)")
+ .HasColumnName("Message");
+
+ b.Property("RunTime")
+ .HasColumnType("datetime(6)");
+
+ 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/20220109030916_Add-Module-Task-Management.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220109030916_Add-Module-Task-Management.cs
new file mode 100644
index 000000000..1c04c8779
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Migrations/20220109030916_Add-Module-Task-Management.cs
@@ -0,0 +1,108 @@
+using System;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace LY.MicroService.TaskManagement.Migrations
+{
+ public partial class AddModuleTaskManagement : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AlterDatabase()
+ .Annotation("MySql:CharSet", "utf8mb4");
+
+ migrationBuilder.CreateTable(
+ name: "TK_BackgroundJobLogs",
+ columns: table => new
+ {
+ Id = table.Column(type: "bigint", nullable: false)
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+ JobId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
+ JobName = table.Column(type: "varchar(100)", maxLength: 100, nullable: true)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ JobGroup = table.Column