diff --git a/docs/en/framework/infrastructure/background-jobs/hangfire.md b/docs/en/framework/infrastructure/background-jobs/hangfire.md index 49f280f1f1..3ea466d83b 100644 --- a/docs/en/framework/infrastructure/background-jobs/hangfire.md +++ b/docs/en/framework/infrastructure/background-jobs/hangfire.md @@ -149,7 +149,7 @@ namespace MyProject Hangfire Dashboard provides information about your background jobs, including method names and serialized arguments as well as gives you an opportunity to manage them by performing different actions – retry, delete, trigger, etc. So it is important to restrict access to the Dashboard. To make it secure by default, only local requests are allowed, however you can change this by following the [official documentation](http://docs.hangfire.io/en/latest/configuration/using-dashboard.html) of Hangfire. -When you enqueue jobs via anonymous handlers (`IBackgroundJobManager.EnqueueAsync(string jobName, object args)` + `IAnonymousJobHandlerRegistry`), ABP uses an internal transport job name (`AnonymousJob`), but the Hangfire dashboard display name tries to show the effective job name from payload (for example, `ProcessOrder`). +When you enqueue jobs via anonymous handlers (`IBackgroundJobManager.EnqueueAsync(string jobName, object args)` + `IAnonymousJobHandlerRegistry`), ABP uses an internal transport job name (`Abp.AnonymousJob`), but the Hangfire dashboard display name tries to show the effective job name from payload (for example, `ProcessOrder`). You can integrate the Hangfire dashboard to [ABP authorization system](../../fundamentals/authorization/index.md) using the **AbpHangfireAuthorizationFilter** class. This class is defined in the `Volo.Abp.Hangfire` package. The following example, checks if the current user is logged in to the application: diff --git a/docs/en/framework/infrastructure/background-jobs/index.md b/docs/en/framework/infrastructure/background-jobs/index.md index 19a371266f..61a4171b49 100644 --- a/docs/en/framework/infrastructure/background-jobs/index.md +++ b/docs/en/framework/infrastructure/background-jobs/index.md @@ -261,7 +261,7 @@ Then enqueue it by name: await _backgroundJobManager.EnqueueAsync("ProcessOrder", new { OrderId = "42" }); ``` -ABP keeps a stable internal transport job name (`AnonymousJob`) for provider compatibility, while preserving your effective job name (`ProcessOrder`) in the payload. +ABP keeps a stable internal transport job name (`Abp.AnonymousJob`) for provider compatibility, while preserving your effective job name (`ProcessOrder`) in the payload. ### Disable Job Execution diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs index cb2f3853c1..f98d2d89f4 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs @@ -96,6 +96,8 @@ public class AbpBackgroundJobOptions public void AddAnonymousJobHandler(string jobName, Action handler) { + Check.NotNull(handler, nameof(handler)); + AddAnonymousJobHandler(jobName, (context, ct) => { handler(context, ct); diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AnonymousJobArgs.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AnonymousJobArgs.cs index 09bac99878..09f9dc0f9f 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AnonymousJobArgs.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AnonymousJobArgs.cs @@ -1,9 +1,9 @@ namespace Volo.Abp.BackgroundJobs; -[BackgroundJobName("AnonymousJob")] +[BackgroundJobName(JobNameConstant)] public class AnonymousJobArgs { - public const string JobNameConstant = "AnonymousJob"; + public const string JobNameConstant = "Abp.AnonymousJob"; public string JobName { get; } diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AnonymousJobHandlerRegistry.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AnonymousJobHandlerRegistry.cs index bb36a8d454..24810d7de9 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AnonymousJobHandlerRegistry.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AnonymousJobHandlerRegistry.cs @@ -27,6 +27,8 @@ public class AnonymousJobHandlerRegistry : IAnonymousJobHandlerRegistry, ISingle public virtual void Register(string jobName, Action handler) { + Check.NotNull(handler, nameof(handler)); + Register(jobName, (context, ct) => { handler(context, ct); @@ -36,16 +38,20 @@ public class AnonymousJobHandlerRegistry : IAnonymousJobHandlerRegistry, ISingle public virtual bool Unregister(string jobName) { + Check.NotNullOrWhiteSpace(jobName, nameof(jobName)); return _handlers.TryRemove(jobName, out _); } public virtual bool IsRegistered(string jobName) { + Check.NotNullOrWhiteSpace(jobName, nameof(jobName)); return _handlers.ContainsKey(jobName) || _options.IsAnonymousJobRegistered(jobName); } public virtual Func? Get(string jobName) { + Check.NotNullOrWhiteSpace(jobName, nameof(jobName)); + if (_handlers.TryGetValue(jobName, out var handler)) { return handler; diff --git a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs index 67406f2b8d..9d84f1f329 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs @@ -77,7 +77,9 @@ public class HangfireBackgroundJobManager : IBackgroundJobManager, ITransientDep protected virtual bool ShouldWrapAsAnonymousJob(string jobName) { - return jobName != AnonymousJobArgs.JobNameConstant && AnonymousJobHandlerRegistry.IsRegistered(jobName); + return jobName != AnonymousJobArgs.JobNameConstant && + AnonymousJobHandlerRegistry.IsRegistered(jobName) && + BackgroundJobOptions.Value.GetJobOrNull(jobName) == null; } protected virtual string GetQueueName(Type argsType) diff --git a/framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzBackgroundJobManager.cs b/framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzBackgroundJobManager.cs index 4d52498f84..a30b8bc9dd 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzBackgroundJobManager.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzBackgroundJobManager.cs @@ -18,17 +18,24 @@ public class QuartzBackgroundJobManager : IBackgroundJobManager, ITransientDepen protected IScheduler Scheduler { get; } protected AbpBackgroundJobQuartzOptions Options { get; } + protected AbpBackgroundJobOptions BackgroundJobOptions { get; } protected IJsonSerializer JsonSerializer { get; } protected IAnonymousJobHandlerRegistry AnonymousJobHandlerRegistry { get; } public ILogger Logger { get; set; } - public QuartzBackgroundJobManager(IScheduler scheduler, IOptions options, IJsonSerializer jsonSerializer, IAnonymousJobHandlerRegistry anonymousJobHandlerRegistry) + public QuartzBackgroundJobManager( + IScheduler scheduler, + IOptions options, + IOptions backgroundJobOptions, + IJsonSerializer jsonSerializer, + IAnonymousJobHandlerRegistry anonymousJobHandlerRegistry) { Scheduler = scheduler; JsonSerializer = jsonSerializer; Options = options.Value; + BackgroundJobOptions = backgroundJobOptions.Value; AnonymousJobHandlerRegistry = anonymousJobHandlerRegistry; Logger = NullLogger.Instance; } @@ -59,7 +66,9 @@ public class QuartzBackgroundJobManager : IBackgroundJobManager, ITransientDepen protected virtual bool ShouldWrapAsAnonymousJob(string jobName) { - return jobName != AnonymousJobArgs.JobNameConstant && AnonymousJobHandlerRegistry.IsRegistered(jobName); + return jobName != AnonymousJobArgs.JobNameConstant && + AnonymousJobHandlerRegistry.IsRegistered(jobName) && + BackgroundJobOptions.GetJobOrNull(jobName) == null; } public virtual async Task ReEnqueueAsync(TArgs args, int retryCount, int retryIntervalMillisecond, diff --git a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/RabbitMqBackgroundJobManager.cs b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/RabbitMqBackgroundJobManager.cs index 5483a3094e..71510e83ff 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/RabbitMqBackgroundJobManager.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/RabbitMqBackgroundJobManager.cs @@ -2,6 +2,7 @@ using System; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; using Volo.Abp.Json; @@ -12,13 +13,19 @@ public class RabbitMqBackgroundJobManager : IBackgroundJobManager, ITransientDep { protected IJobQueueManager JobQueueManager { get; } protected IAnonymousJobHandlerRegistry AnonymousJobHandlerRegistry { get; } + protected AbpBackgroundJobOptions BackgroundJobOptions { get; } protected IJsonSerializer JsonSerializer { get; } public ILogger Logger { get; set; } - public RabbitMqBackgroundJobManager(IJobQueueManager jobQueueManager, IAnonymousJobHandlerRegistry anonymousJobHandlerRegistry, IJsonSerializer jsonSerializer) + public RabbitMqBackgroundJobManager( + IJobQueueManager jobQueueManager, + IAnonymousJobHandlerRegistry anonymousJobHandlerRegistry, + IOptions backgroundJobOptions, + IJsonSerializer jsonSerializer) { JobQueueManager = jobQueueManager; AnonymousJobHandlerRegistry = anonymousJobHandlerRegistry; + BackgroundJobOptions = backgroundJobOptions.Value; JsonSerializer = jsonSerializer; Logger = NullLogger.Instance; } @@ -56,6 +63,8 @@ public class RabbitMqBackgroundJobManager : IBackgroundJobManager, ITransientDep protected virtual bool ShouldWrapAsAnonymousJob(string jobName) { - return jobName != AnonymousJobArgs.JobNameConstant && AnonymousJobHandlerRegistry.IsRegistered(jobName); + return jobName != AnonymousJobArgs.JobNameConstant && + AnonymousJobHandlerRegistry.IsRegistered(jobName) && + BackgroundJobOptions.GetJobOrNull(jobName) == null; } } diff --git a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpTickerQBackgroundJobManager.cs b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpTickerQBackgroundJobManager.cs index 54b97adf30..82df9e2fe7 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpTickerQBackgroundJobManager.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpTickerQBackgroundJobManager.cs @@ -65,7 +65,9 @@ public class AbpTickerQBackgroundJobManager : IBackgroundJobManager, ITransientD protected virtual bool ShouldWrapAsAnonymousJob(string jobName) { - return jobName != AnonymousJobArgs.JobNameConstant && AnonymousJobHandlerRegistry.IsRegistered(jobName); + return jobName != AnonymousJobArgs.JobNameConstant && + AnonymousJobHandlerRegistry.IsRegistered(jobName) && + Options.GetJobOrNull(jobName) == null; } protected virtual async Task EnqueueAsync(BackgroundJobConfiguration job, object args, BackgroundJobPriority priority, TimeSpan? delay) diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/DefaultBackgroundJobManager.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/DefaultBackgroundJobManager.cs index 5669525db9..4714e11e72 100644 --- a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/DefaultBackgroundJobManager.cs +++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/DefaultBackgroundJobManager.cs @@ -87,6 +87,8 @@ public class DefaultBackgroundJobManager : IBackgroundJobManager, ITransientDepe protected virtual bool ShouldWrapAsAnonymousJob(string jobName) { - return jobName != AnonymousJobArgs.JobNameConstant && AnonymousJobHandlerRegistry.IsRegistered(jobName); + return jobName != AnonymousJobArgs.JobNameConstant && + AnonymousJobHandlerRegistry.IsRegistered(jobName) && + BackgroundJobOptions.Value.GetJobOrNull(jobName) == null; } } diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobManager_Tests.cs b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobManager_Tests.cs index bb8d05bf86..948c1b9f4a 100644 --- a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobManager_Tests.cs +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobManager_Tests.cs @@ -10,11 +10,13 @@ public class BackgroundJobManager_Tests : BackgroundJobsTestBase { private readonly IBackgroundJobManager _backgroundJobManager; private readonly IBackgroundJobStore _backgroundJobStore; + private readonly IAnonymousJobHandlerRegistry _anonymousJobHandlerRegistry; public BackgroundJobManager_Tests() { _backgroundJobManager = GetRequiredService(); _backgroundJobStore = GetRequiredService(); + _anonymousJobHandlerRegistry = GetRequiredService(); } [Fact] @@ -75,4 +77,19 @@ public class BackgroundJobManager_Tests : BackgroundJobsTestBase jobInfo.JobArgs.ShouldContain("TestAnonymousJob"); jobInfo.JobArgs.ShouldContain("ORD-001"); } + + [Fact] + public async Task Should_Not_Wrap_If_Typed_Job_Exists_For_Same_Name() + { + var typedJobName = BackgroundJobNameAttribute.GetName(); + _anonymousJobHandlerRegistry.Register(typedJobName, (_, _) => Task.CompletedTask); + + var jobIdAsString = await _backgroundJobManager.EnqueueAsync(typedJobName, new { Value = "42" }); + jobIdAsString.ShouldNotBe(default); + + var jobInfo = await _backgroundJobStore.FindAsync(Guid.Parse(jobIdAsString)); + jobInfo.ShouldNotBeNull(); + jobInfo.JobName.ShouldBe(typedJobName); + jobInfo.JobName.ShouldNotBe(AnonymousJobArgs.JobNameConstant); + } }