mirror of https://github.com/abpframework/abp.git
Browse Source
Introduce anonymous/background-job-by-name support: add AnonymousJobArgs, IAnonymousJobHandlerRegistry and AnonymousJobHandlerRegistry, and an AnonymousJobExecutorAsyncBackgroundJob to execute JSON-based anonymous handlers. AbpBackgroundJobOptions now stores anonymous handlers and exposes registration/query helpers. Updated background job managers (Default, Hangfire, Quartz, RabbitMQ, TickerQ) to wrap registered anonymous jobs into AnonymousJobArgs when enqueuing and to depend on the handler registry and JSON serializer where needed. Removed the old dynamic handler types/APIs (DynamicBackgroundJobContext, IDynamicBackgroundJobHandlerProvider, DynamicBackgroundJobHandlerProvider) and related dynamic handling code; BackgroundJobConfiguration simplified (JobType non-nullable) and JobExecutionContext no longer carries JobName. Tests and demo code updated to use anonymous handlers and tracking. This change centralizes runtime-registered handlers keyed by job name and standardizes anonymous job payloads as JSON.pull/25059/head
31 changed files with 334 additions and 247 deletions
@ -0,0 +1,9 @@ |
|||||
|
{ |
||||
|
"version": 1, |
||||
|
"transcripts": { |
||||
|
"C:\\Users\\salih\\.cursor\\projects\\d-GitHub2-abp\\agent-transcripts\\ded34ec4-ff99-404a-8b16-10baf3c5d9f5\\ded34ec4-ff99-404a-8b16-10baf3c5d9f5.jsonl": { |
||||
|
"mtimeMs": 1773090599259, |
||||
|
"lastProcessedAt": "2026-03-10T00:18:00.000Z" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
{ |
||||
|
"version": 1, |
||||
|
"lastRunAtMs": 1773090515725, |
||||
|
"turnsSinceLastRun": 5, |
||||
|
"lastTranscriptMtimeMs": 1773090515368, |
||||
|
"lastProcessedGenerationId": "b1b803a9-44bb-4047-a116-4c108a6dadd1", |
||||
|
"trialStartedAtMs": null |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
namespace Volo.Abp.BackgroundJobs; |
||||
|
|
||||
|
[BackgroundJobName("AnonymousJob")] |
||||
|
public class AnonymousJobArgs |
||||
|
{ |
||||
|
public const string JobNameConstant = "AnonymousJob"; |
||||
|
|
||||
|
public string JobName { get; } |
||||
|
|
||||
|
public string JsonData { get; } |
||||
|
|
||||
|
public AnonymousJobArgs(string jobName, string jsonData) |
||||
|
{ |
||||
|
JobName = Check.NotNullOrWhiteSpace(jobName, nameof(jobName)); |
||||
|
JsonData = Check.NotNull(jsonData, nameof(jsonData)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Concurrent; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.BackgroundJobs; |
||||
|
|
||||
|
public class AnonymousJobHandlerRegistry : IAnonymousJobHandlerRegistry, ISingletonDependency |
||||
|
{ |
||||
|
private readonly ConcurrentDictionary<string, Func<string, IServiceProvider, CancellationToken, Task>> _handlers = new(); |
||||
|
private readonly AbpBackgroundJobOptions _options; |
||||
|
|
||||
|
public AnonymousJobHandlerRegistry(IOptions<AbpBackgroundJobOptions> options) |
||||
|
{ |
||||
|
_options = options.Value; |
||||
|
} |
||||
|
|
||||
|
public virtual void Register(string jobName, Func<string, IServiceProvider, CancellationToken, Task> handler) |
||||
|
{ |
||||
|
Check.NotNullOrWhiteSpace(jobName, nameof(jobName)); |
||||
|
Check.NotNull(handler, nameof(handler)); |
||||
|
|
||||
|
_handlers[jobName] = handler; |
||||
|
} |
||||
|
|
||||
|
public virtual void Register(string jobName, Action<string, IServiceProvider, CancellationToken> handler) |
||||
|
{ |
||||
|
Register(jobName, (jsonData, sp, ct) => |
||||
|
{ |
||||
|
handler(jsonData, sp, ct); |
||||
|
return Task.CompletedTask; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public virtual bool Unregister(string jobName) |
||||
|
{ |
||||
|
return _handlers.TryRemove(jobName, out _); |
||||
|
} |
||||
|
|
||||
|
public virtual bool IsRegistered(string jobName) |
||||
|
{ |
||||
|
return _handlers.ContainsKey(jobName) || _options.IsAnonymousJobRegistered(jobName); |
||||
|
} |
||||
|
|
||||
|
public virtual Func<string, IServiceProvider, CancellationToken, Task>? Get(string jobName) |
||||
|
{ |
||||
|
if (_handlers.TryGetValue(jobName, out var handler)) |
||||
|
{ |
||||
|
return handler; |
||||
|
} |
||||
|
|
||||
|
return _options.TryGetAnonymousHandler(jobName, out handler) ? handler : null; |
||||
|
} |
||||
|
} |
||||
@ -1,25 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Threading; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
|
|
||||
namespace Volo.Abp.BackgroundJobs; |
|
||||
|
|
||||
public class DynamicBackgroundJobContext : IServiceProviderAccessor |
|
||||
{ |
|
||||
public IServiceProvider ServiceProvider { get; } |
|
||||
|
|
||||
public Dictionary<string, object> Args { get; } |
|
||||
|
|
||||
public CancellationToken CancellationToken { get; } |
|
||||
|
|
||||
public DynamicBackgroundJobContext( |
|
||||
IServiceProvider serviceProvider, |
|
||||
Dictionary<string, object> args, |
|
||||
CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
ServiceProvider = serviceProvider; |
|
||||
Args = args; |
|
||||
CancellationToken = cancellationToken; |
|
||||
} |
|
||||
} |
|
||||
@ -1,36 +0,0 @@ |
|||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
|
|
||||
namespace Volo.Abp.BackgroundJobs; |
|
||||
|
|
||||
public class DynamicBackgroundJobHandlerProvider : IDynamicBackgroundJobHandlerProvider, ISingletonDependency |
|
||||
{ |
|
||||
protected AbpBackgroundJobOptions Options { get; } |
|
||||
|
|
||||
public DynamicBackgroundJobHandlerProvider(IOptions<AbpBackgroundJobOptions> options) |
|
||||
{ |
|
||||
Options = options.Value; |
|
||||
} |
|
||||
|
|
||||
public virtual void Register(string jobName, Func<DynamicBackgroundJobContext, Task> handler) |
|
||||
{ |
|
||||
Options.AddDynamicJob(jobName, handler); |
|
||||
} |
|
||||
|
|
||||
public virtual void Register(string jobName, Action<DynamicBackgroundJobContext> handler) |
|
||||
{ |
|
||||
Options.AddDynamicJob(jobName, handler); |
|
||||
} |
|
||||
|
|
||||
public virtual bool Unregister(string jobName) |
|
||||
{ |
|
||||
return Options.RemoveDynamicJob(jobName); |
|
||||
} |
|
||||
|
|
||||
public virtual bool IsRegistered(string jobName) |
|
||||
{ |
|
||||
return Options.GetJobOrNull(jobName)?.IsDynamic == true; |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,18 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.BackgroundJobs; |
||||
|
|
||||
|
public interface IAnonymousJobHandlerRegistry |
||||
|
{ |
||||
|
void Register(string jobName, Func<string, IServiceProvider, System.Threading.CancellationToken, Task> handler); |
||||
|
|
||||
|
void Register(string jobName, Action<string, IServiceProvider, System.Threading.CancellationToken> handler); |
||||
|
|
||||
|
bool Unregister(string jobName); |
||||
|
|
||||
|
bool IsRegistered(string jobName); |
||||
|
|
||||
|
Func<string, IServiceProvider, System.Threading.CancellationToken, Task>? Get(string jobName); |
||||
|
} |
||||
@ -1,15 +0,0 @@ |
|||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace Volo.Abp.BackgroundJobs; |
|
||||
|
|
||||
public interface IDynamicBackgroundJobHandlerProvider |
|
||||
{ |
|
||||
void Register(string jobName, Func<DynamicBackgroundJobContext, Task> handler); |
|
||||
|
|
||||
void Register(string jobName, Action<DynamicBackgroundJobContext> handler); |
|
||||
|
|
||||
bool Unregister(string jobName); |
|
||||
|
|
||||
bool IsRegistered(string jobName); |
|
||||
} |
|
||||
@ -0,0 +1,35 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Threading; |
||||
|
|
||||
|
namespace Volo.Abp.BackgroundJobs; |
||||
|
|
||||
|
public class AnonymousJobExecutorAsyncBackgroundJob : AsyncBackgroundJob<AnonymousJobArgs>, ITransientDependency |
||||
|
{ |
||||
|
protected IAnonymousJobHandlerRegistry HandlerRegistry { get; } |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
protected ICancellationTokenProvider CancellationTokenProvider { get; } |
||||
|
|
||||
|
public AnonymousJobExecutorAsyncBackgroundJob( |
||||
|
IAnonymousJobHandlerRegistry handlerRegistry, |
||||
|
IServiceProvider serviceProvider, |
||||
|
ICancellationTokenProvider cancellationTokenProvider) |
||||
|
{ |
||||
|
HandlerRegistry = handlerRegistry; |
||||
|
ServiceProvider = serviceProvider; |
||||
|
CancellationTokenProvider = cancellationTokenProvider; |
||||
|
} |
||||
|
|
||||
|
public override async Task ExecuteAsync(AnonymousJobArgs args) |
||||
|
{ |
||||
|
var handler = HandlerRegistry.Get(args.JobName); |
||||
|
if (handler == null) |
||||
|
{ |
||||
|
throw new AbpException("No anonymous job handler registered for: " + args.JobName); |
||||
|
} |
||||
|
|
||||
|
await handler(args.JsonData, ServiceProvider, CancellationTokenProvider.Token); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.BackgroundJobs; |
||||
|
|
||||
|
public class AnonymousJobExecutionTracker |
||||
|
{ |
||||
|
public List<string> ExecutedJsonData { get; } = new(); |
||||
|
} |
||||
@ -1,8 +0,0 @@ |
|||||
using System.Collections.Generic; |
|
||||
|
|
||||
namespace Volo.Abp.BackgroundJobs; |
|
||||
|
|
||||
public class DynamicJobExecutionTracker |
|
||||
{ |
|
||||
public List<Dictionary<string, object>> ExecutedArgs { get; } = new(); |
|
||||
} |
|
||||
@ -0,0 +1,25 @@ |
|||||
|
services: |
||||
|
sqlserver: |
||||
|
image: mcr.microsoft.com/mssql/server:2022-latest |
||||
|
environment: |
||||
|
ACCEPT_EULA: "Y" |
||||
|
MSSQL_SA_PASSWORD: "YourStrong!Passw0rd" |
||||
|
ports: |
||||
|
- "1433:1433" |
||||
|
volumes: |
||||
|
- sqlserver-data:/var/opt/mssql |
||||
|
|
||||
|
rabbitmq: |
||||
|
image: rabbitmq:4-management |
||||
|
ports: |
||||
|
- "5672:5672" |
||||
|
- "15672:15672" |
||||
|
environment: |
||||
|
RABBITMQ_DEFAULT_USER: "guest" |
||||
|
RABBITMQ_DEFAULT_PASS: "guest" |
||||
|
volumes: |
||||
|
- rabbitmq-data:/var/lib/rabbitmq |
||||
|
|
||||
|
volumes: |
||||
|
sqlserver-data: |
||||
|
rabbitmq-data: |
||||
Loading…
Reference in new issue