From b9a265a831757bc0a3cef96c479c56ada12c07e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SAL=C4=B0H=20=C3=96ZKARA?= Date: Wed, 11 Mar 2026 10:44:58 +0300 Subject: [PATCH] Defer dynamic handler registration and fix outcomes Move DynamicBackgroundWorkerHandlerRegistry.Register calls to after scheduling to avoid registering handlers when scheduling fails. Adjust Quartz behaviour to return actual outcomes: only unregister when DeleteJob reports deletion and return whether RescheduleJob succeeded. Convert TickerQ RemoveAsync to a non-async Task (using Task.FromResult) and move its registration similarly. Update test to poll with a timeout (instead of a fixed 500ms delay) to wait for background worker execution. --- .../Hangfire/HangfireBackgroundWorkerManager.cs | 4 ++-- .../Quartz/QuartzBackgroundWorkerManager.cs | 17 ++++++++++------- .../AbpTickerQBackgroundWorkerManager.cs | 10 +++++----- .../BackgroundWorkerManager.cs | 4 ++-- .../DynamicBackgroundWorkerManager_Tests.cs | 8 +++++++- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs index 6cd778c1fd..5d82c14ba9 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs @@ -165,8 +165,6 @@ public class HangfireBackgroundWorkerManager : BackgroundWorkerManager, ISinglet Check.NotNull(schedule, nameof(schedule)); Check.NotNull(handler, nameof(handler)); - DynamicBackgroundWorkerHandlerRegistry.Register(workerName, handler); - var cronExpression = schedule.CronExpression; if (cronExpression.IsNullOrWhiteSpace()) { @@ -204,6 +202,8 @@ public class HangfireBackgroundWorkerManager : BackgroundWorkerManager, ISinglet }); } + DynamicBackgroundWorkerHandlerRegistry.Register(workerName, handler); + return Task.CompletedTask; } diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs index e0d30b7d3b..a696f6e8ac 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs @@ -130,8 +130,6 @@ public class QuartzBackgroundWorkerManager : BackgroundWorkerManager, ISingleton Check.NotNull(schedule, nameof(schedule)); Check.NotNull(handler, nameof(handler)); - DynamicBackgroundWorkerHandlerRegistry.Register(workerName, handler); - if (schedule.Period == null && schedule.CronExpression.IsNullOrWhiteSpace()) { throw new AbpException($"Both 'Period' and 'CronExpression' are not set for dynamic worker {workerName}. You must set at least one of them."); @@ -170,6 +168,8 @@ public class QuartzBackgroundWorkerManager : BackgroundWorkerManager, ISingleton { await Scheduler.ScheduleJob(jobDetail, trigger, cancellationToken); } + + DynamicBackgroundWorkerHandlerRegistry.Register(workerName, handler); } public override async Task RemoveAsync(string workerName, CancellationToken cancellationToken = default) @@ -182,10 +182,13 @@ public class QuartzBackgroundWorkerManager : BackgroundWorkerManager, ISingleton } var jobKey = new JobKey($"DynamicWorker:{workerName}"); - await Scheduler.DeleteJob(jobKey, cancellationToken); - DynamicBackgroundWorkerHandlerRegistry.Unregister(workerName); + var deleted = await Scheduler.DeleteJob(jobKey, cancellationToken); + if (deleted) + { + DynamicBackgroundWorkerHandlerRegistry.Unregister(workerName); + } - return true; + return deleted; } public override async Task UpdateScheduleAsync(string workerName, DynamicBackgroundWorkerSchedule schedule, CancellationToken cancellationToken = default) @@ -218,8 +221,8 @@ public class QuartzBackgroundWorkerManager : BackgroundWorkerManager, ISingleton builder.WithInterval(TimeSpan.FromMilliseconds(schedule.Period!.Value)).RepeatForever()); } - await Scheduler.RescheduleJob(triggerKey, triggerBuilder.Build(), cancellationToken); + var result = await Scheduler.RescheduleJob(triggerKey, triggerBuilder.Build(), cancellationToken); - return true; + return result != null; } } diff --git a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQBackgroundWorkerManager.cs index 6bf9e305e8..fbfc9eb47d 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQBackgroundWorkerManager.cs @@ -105,8 +105,6 @@ public class AbpTickerQBackgroundWorkerManager : BackgroundWorkerManager, ISingl Check.NotNull(schedule, nameof(schedule)); Check.NotNull(handler, nameof(handler)); - DynamicBackgroundWorkerHandlerRegistry.Register(workerName, handler); - var cronExpression = schedule.CronExpression ?? GetCron(schedule.Period ?? DynamicBackgroundWorkerSchedule.DefaultPeriod); var functionName = $"DynamicWorker:{workerName}"; @@ -137,15 +135,17 @@ public class AbpTickerQBackgroundWorkerManager : BackgroundWorkerManager, ISingl Function = functionName, Expression = cronExpression }); + + DynamicBackgroundWorkerHandlerRegistry.Register(workerName, handler); } - public override async Task RemoveAsync(string workerName, CancellationToken cancellationToken = default) + public override Task RemoveAsync(string workerName, CancellationToken cancellationToken = default) { Check.NotNullOrWhiteSpace(workerName, nameof(workerName)); if (!DynamicBackgroundWorkerHandlerRegistry.IsRegistered(workerName)) { - return false; + return Task.FromResult(false); } var functionName = $"DynamicWorker:{workerName}"; @@ -153,7 +153,7 @@ public class AbpTickerQBackgroundWorkerManager : BackgroundWorkerManager, ISingl AbpTickerQBackgroundWorkersProvider.BackgroundWorkers.Remove(functionName); DynamicBackgroundWorkerHandlerRegistry.Unregister(workerName); - return true; + return Task.FromResult(true); } public override async Task UpdateScheduleAsync(string workerName, DynamicBackgroundWorkerSchedule schedule, CancellationToken cancellationToken = default) diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerManager.cs index a5568cc5d0..a1f9f78fcd 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerManager.cs @@ -71,13 +71,13 @@ public class BackgroundWorkerManager : IBackgroundWorkerManager, ISingletonDepen Check.NotNull(schedule, nameof(schedule)); Check.NotNull(handler, nameof(handler)); - DynamicBackgroundWorkerHandlerRegistry.Register(workerName, handler); - if (schedule.Period == null && !string.IsNullOrWhiteSpace(schedule.CronExpression)) { throw new AbpException("Default background worker manager does not support cron expression without period."); } + DynamicBackgroundWorkerHandlerRegistry.Register(workerName, handler); + var timer = ServiceProvider.GetRequiredService(); var serviceScopeFactory = ServiceProvider.GetRequiredService(); var worker = new InMemoryDynamicBackgroundWorker( diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/DynamicBackgroundWorkerManager_Tests.cs b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/DynamicBackgroundWorkerManager_Tests.cs index bd2685da04..3c2977e53c 100644 --- a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/DynamicBackgroundWorkerManager_Tests.cs +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/DynamicBackgroundWorkerManager_Tests.cs @@ -121,7 +121,13 @@ public class DynamicBackgroundWorkerManager_Tests : BackgroundJobsTestBase result.ShouldBeTrue(); _handlerRegistry.IsRegistered(workerName).ShouldBeTrue(); - await Task.Delay(500); + var timeout = TimeSpan.FromSeconds(5); + var startTime = DateTime.UtcNow; + while (executionCount == 0 && DateTime.UtcNow - startTime < timeout) + { + await Task.Delay(50); + } + executionCount.ShouldBeGreaterThan(0); }