diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireDynamicBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireDynamicBackgroundWorkerManager.cs index a9b9026606..d54e37c534 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireDynamicBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireDynamicBackgroundWorkerManager.cs @@ -13,7 +13,11 @@ using Volo.Abp.Hangfire; namespace Volo.Abp.BackgroundWorkers.Hangfire; [Dependency(ReplaceServices = true)] -public class HangfireDynamicBackgroundWorkerManager : IDynamicBackgroundWorkerManager, ISingletonDependency +public class HangfireDynamicBackgroundWorkerManager : + IDynamicBackgroundWorkerManager, + ISupportsRuntimeRegistration, + ISupportsCronScheduling, + ISingletonDependency { protected IServiceProvider ServiceProvider { get; } protected IDynamicBackgroundWorkerHandlerRegistry HandlerRegistry { get; } diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzDynamicBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzDynamicBackgroundWorkerManager.cs index 5a729ad974..2f098d6ab4 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzDynamicBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzDynamicBackgroundWorkerManager.cs @@ -10,7 +10,11 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.BackgroundWorkers.Quartz; [Dependency(ReplaceServices = true)] -public class QuartzDynamicBackgroundWorkerManager : IDynamicBackgroundWorkerManager, ISingletonDependency +public class QuartzDynamicBackgroundWorkerManager : + IDynamicBackgroundWorkerManager, + ISupportsRuntimeRegistration, + ISupportsCronScheduling, + ISingletonDependency { public const string DynamicWorkerNameKey = "AbpDynamicWorkerName"; diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/DefaultDynamicBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/DefaultDynamicBackgroundWorkerManager.cs index 439e61de21..62dce443a8 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/DefaultDynamicBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/DefaultDynamicBackgroundWorkerManager.cs @@ -10,7 +10,10 @@ using Volo.Abp.Threading; namespace Volo.Abp.BackgroundWorkers; -public class DefaultDynamicBackgroundWorkerManager : IDynamicBackgroundWorkerManager, ISingletonDependency +public class DefaultDynamicBackgroundWorkerManager : + IDynamicBackgroundWorkerManager, + ISupportsRuntimeRegistration, + ISingletonDependency { protected IServiceProvider ServiceProvider { get; } public ILogger Logger { get; set; } @@ -39,11 +42,11 @@ public class DefaultDynamicBackgroundWorkerManager : IDynamicBackgroundWorkerMan schedule.Validate(); - if (schedule.Period == null) + if (!schedule.CronExpression.IsNullOrWhiteSpace()) { throw new AbpException( - $"The default in-memory background worker manager does not support CronExpression without Period for dynamic worker '{workerName}'. " + - "Please set Period, or use a scheduler-backed provider (Hangfire, Quartz, TickerQ)."); + $"The default in-memory background worker manager does not support CronExpression for dynamic worker '{workerName}'. " + + "Please clear CronExpression and use Period-based scheduling, or use a scheduler-backed provider (Hangfire or Quartz)."); } await _semaphore.WaitAsync(cancellationToken); @@ -102,11 +105,11 @@ public class DefaultDynamicBackgroundWorkerManager : IDynamicBackgroundWorkerMan schedule.Validate(); - if (schedule.Period == null) + if (!schedule.CronExpression.IsNullOrWhiteSpace()) { throw new AbpException( - $"The default in-memory background worker manager does not support CronExpression without Period for dynamic worker '{workerName}'. " + - "Please set Period, or use a scheduler-backed provider (Hangfire, Quartz, TickerQ)."); + $"The default in-memory background worker manager does not support CronExpression for dynamic worker '{workerName}'. " + + "Please clear CronExpression and use Period-based scheduling, or use a scheduler-backed provider (Hangfire or Quartz)."); } await _semaphore.WaitAsync(cancellationToken); diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/IDynamicBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/IDynamicBackgroundWorkerManager.cs index 7e625e7c9c..a897549249 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/IDynamicBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/IDynamicBackgroundWorkerManager.cs @@ -6,6 +6,12 @@ namespace Volo.Abp.BackgroundWorkers; /// /// Manages dynamic background workers that are registered at runtime /// without requiring a strongly-typed worker class. +/// +/// Implementations may differ in capabilities. Check +/// before calling / / , +/// and before passing +/// . +/// /// public interface IDynamicBackgroundWorkerManager { diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/ISupportsCronScheduling.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/ISupportsCronScheduling.cs new file mode 100644 index 0000000000..9160ef368a --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/ISupportsCronScheduling.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.BackgroundWorkers; + +/// +/// Marks a dynamic background worker manager that supports cron-based scheduling. +/// +public interface ISupportsCronScheduling +{ +} diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/ISupportsRuntimeRegistration.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/ISupportsRuntimeRegistration.cs new file mode 100644 index 0000000000..4f343113bf --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/ISupportsRuntimeRegistration.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.BackgroundWorkers; + +/// +/// Marks a dynamic background worker manager that supports registering workers at runtime. +/// +public interface ISupportsRuntimeRegistration +{ +} diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundWorkers/DynamicBackgroundWorkerManager_Tests.cs b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundWorkers/DynamicBackgroundWorkerManager_Tests.cs index a61c99fdc1..955b2104dd 100644 --- a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundWorkers/DynamicBackgroundWorkerManager_Tests.cs +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundWorkers/DynamicBackgroundWorkerManager_Tests.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Shouldly; +using Volo.Abp; using Volo.Abp.BackgroundJobs; using Volo.Abp.BackgroundWorkers; using Xunit; @@ -20,6 +21,13 @@ public class DynamicBackgroundWorkerManager_Tests : BackgroundJobsTestBase _dynamicWorkerManager = GetRequiredService(); } + [Fact] + public void Should_Report_Provider_Capabilities_Using_Marker_Interfaces() + { + (_dynamicWorkerManager is ISupportsRuntimeRegistration).ShouldBeTrue(); + (_dynamicWorkerManager is ISupportsCronScheduling).ShouldBeFalse(); + } + [Fact] public async Task Should_Register_Dynamic_Worker() { @@ -235,6 +243,49 @@ public class DynamicBackgroundWorkerManager_Tests : BackgroundJobsTestBase }); } + [Fact] + public async Task Should_Throw_When_CronExpression_Is_Set() + { + var workerName = "dynamic-worker-" + Guid.NewGuid(); + + await Assert.ThrowsAsync(async () => + { + await _dynamicWorkerManager.AddAsync( + workerName, + new DynamicBackgroundWorkerSchedule + { + Period = 1000, + CronExpression = "0 */5 * * * *" + }, + (_, _) => Task.CompletedTask + ); + }); + } + + [Fact] + public async Task Should_Throw_When_CronExpression_Is_Set_On_UpdateSchedule() + { + var workerName = "dynamic-worker-" + Guid.NewGuid(); + + await _dynamicWorkerManager.AddAsync( + workerName, + new DynamicBackgroundWorkerSchedule { Period = 1000 }, + (_, _) => Task.CompletedTask + ); + + await Assert.ThrowsAsync(async () => + { + await _dynamicWorkerManager.UpdateScheduleAsync( + workerName, + new DynamicBackgroundWorkerSchedule + { + Period = 1000, + CronExpression = "0 */5 * * * *" + } + ); + }); + } + [Fact] public async Task Should_Continue_Running_After_Handler_Throws_Exception() {