Browse Source

Use Abp.AnonymousJob name and add validation

Rename the internal anonymous transport job name from "AnonymousJob" to "Abp.AnonymousJob" and update docs accordingly. Add null/whitespace argument checks (Check.NotNull / Check.NotNullOrWhiteSpace) in anonymous handler registration and lookup APIs. Change background job managers (Hangfire, Quartz, RabbitMQ, TickerQ, Default) to only wrap jobs as anonymous when an anonymous handler is registered and there is no typed job configuration (check via BackgroundJobOptions.GetJobOrNull). Wire AbpBackgroundJobOptions into affected managers and update tests with a new case verifying that a typed job prevents anonymous wrapping.
pull/25059/head
SALİH ÖZKARA 3 weeks ago
parent
commit
0b40f2c0f1
  1. 2
      docs/en/framework/infrastructure/background-jobs/hangfire.md
  2. 2
      docs/en/framework/infrastructure/background-jobs/index.md
  3. 2
      framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs
  4. 4
      framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AnonymousJobArgs.cs
  5. 6
      framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AnonymousJobHandlerRegistry.cs
  6. 4
      framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs
  7. 13
      framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzBackgroundJobManager.cs
  8. 13
      framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/RabbitMqBackgroundJobManager.cs
  9. 4
      framework/src/Volo.Abp.BackgroundJobs.TickerQ/Volo/Abp/BackgroundJobs/TickerQ/AbpTickerQBackgroundJobManager.cs
  10. 4
      framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/DefaultBackgroundJobManager.cs
  11. 17
      framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobManager_Tests.cs

2
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:

2
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

2
framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs

@ -96,6 +96,8 @@ public class AbpBackgroundJobOptions
public void AddAnonymousJobHandler(string jobName, Action<AnonymousJobExecutionContext, CancellationToken> handler)
{
Check.NotNull(handler, nameof(handler));
AddAnonymousJobHandler(jobName, (context, ct) =>
{
handler(context, ct);

4
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; }

6
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<AnonymousJobExecutionContext, CancellationToken> 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<AnonymousJobExecutionContext, CancellationToken, Task>? Get(string jobName)
{
Check.NotNullOrWhiteSpace(jobName, nameof(jobName));
if (_handlers.TryGetValue(jobName, out var handler))
{
return handler;

4
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)

13
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<QuartzBackgroundJobManager> Logger { get; set; }
public QuartzBackgroundJobManager(IScheduler scheduler, IOptions<AbpBackgroundJobQuartzOptions> options, IJsonSerializer jsonSerializer, IAnonymousJobHandlerRegistry anonymousJobHandlerRegistry)
public QuartzBackgroundJobManager(
IScheduler scheduler,
IOptions<AbpBackgroundJobQuartzOptions> options,
IOptions<AbpBackgroundJobOptions> backgroundJobOptions,
IJsonSerializer jsonSerializer,
IAnonymousJobHandlerRegistry anonymousJobHandlerRegistry)
{
Scheduler = scheduler;
JsonSerializer = jsonSerializer;
Options = options.Value;
BackgroundJobOptions = backgroundJobOptions.Value;
AnonymousJobHandlerRegistry = anonymousJobHandlerRegistry;
Logger = NullLogger<QuartzBackgroundJobManager>.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<string> ReEnqueueAsync<TArgs>(TArgs args, int retryCount, int retryIntervalMillisecond,

13
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<RabbitMqBackgroundJobManager> Logger { get; set; }
public RabbitMqBackgroundJobManager(IJobQueueManager jobQueueManager, IAnonymousJobHandlerRegistry anonymousJobHandlerRegistry, IJsonSerializer jsonSerializer)
public RabbitMqBackgroundJobManager(
IJobQueueManager jobQueueManager,
IAnonymousJobHandlerRegistry anonymousJobHandlerRegistry,
IOptions<AbpBackgroundJobOptions> backgroundJobOptions,
IJsonSerializer jsonSerializer)
{
JobQueueManager = jobQueueManager;
AnonymousJobHandlerRegistry = anonymousJobHandlerRegistry;
BackgroundJobOptions = backgroundJobOptions.Value;
JsonSerializer = jsonSerializer;
Logger = NullLogger<RabbitMqBackgroundJobManager>.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;
}
}

4
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<string> EnqueueAsync(BackgroundJobConfiguration job, object args, BackgroundJobPriority priority, TimeSpan? delay)

4
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;
}
}

17
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<IBackgroundJobManager>();
_backgroundJobStore = GetRequiredService<IBackgroundJobStore>();
_anonymousJobHandlerRegistry = GetRequiredService<IAnonymousJobHandlerRegistry>();
}
[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<MyJobArgs>();
_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);
}
}

Loading…
Cancel
Save