diff --git a/docs/migration/v4.md b/docs/migration/v4.md index a63f834..64aaebc 100644 --- a/docs/migration/v4.md +++ b/docs/migration/v4.md @@ -27,4 +27,13 @@ The `AddNCronJob(Delegate)` (Minimal API) was a different static class than the ```diff - IServiceCollection.AddNCronJob(() => {}, "* * * * *"); + NCronJobExtensions.AddNCronJob(services, () => {}, "* * * * *"); -``` \ No newline at end of file +``` + +## `IRuntimeRegistry` is more restrictive +In `v3` the `IRuntimeRegistry` offered the ability to use the whole `NCronJobOptionBuilder` which lead to confusion, especially if done something like this: + +```csharp +runtimeRegistry.AddJob(n => n.AddJob(...).RunAtStartup().AddExceptionHandler()); +``` + +It didn't make sense to add a startup job during runtime. Also adding exception handlers during runtime was out of scope for this feature. Therefore the interface is more restrictive now and only allows to add jobs. \ No newline at end of file diff --git a/src/NCronJob/Configuration/Builder/IRuntimeJobBuilder.cs b/src/NCronJob/Configuration/Builder/IRuntimeJobBuilder.cs new file mode 100644 index 0000000..8a7f540 --- /dev/null +++ b/src/NCronJob/Configuration/Builder/IRuntimeJobBuilder.cs @@ -0,0 +1,37 @@ +namespace NCronJob; + +/// +/// Represents a builder for adding jobs at runtime. +/// +public interface IRuntimeJobBuilder +{ + /// + /// Adds a job to the service collection that gets executed based on the given cron expression. + /// + /// Configures the , like the cron expression or parameters that get passed down. + /// Returns the for chaining. + IRuntimeJobBuilder AddJob(Action? options = null) where TJob : class, IJob; + + /// + /// Adds a job to the service collection that gets executed based on the given cron expression. + /// + /// The type of the job to be added. + /// Configures the , like the cron expression or parameters that get passed down. + /// Returns the for chaining. + IRuntimeJobBuilder AddJob(Type jobType, Action? options = null); + + /// + /// Adds a job using an asynchronous anonymous delegate to the service collection that gets executed based on the given cron expression. + /// + /// The delegate that represents the job to be executed. + /// The cron expression that defines when the job should be executed. + /// The time zone information that the cron expression should be evaluated against. + /// If not set the default time zone is UTC. + /// + /// Sets the job name that can be used to identify and manipulate the job later on. + /// Returns the for chaining. + IRuntimeJobBuilder AddJob(Delegate jobDelegate, + string cronExpression, + TimeZoneInfo? timeZoneInfo = null, + string? jobName = null); +} diff --git a/src/NCronJob/Configuration/Builder/NCronJobOptionBuilder.cs b/src/NCronJob/Configuration/Builder/NCronJobOptionBuilder.cs index 97254b0..9a7640f 100644 --- a/src/NCronJob/Configuration/Builder/NCronJobOptionBuilder.cs +++ b/src/NCronJob/Configuration/Builder/NCronJobOptionBuilder.cs @@ -8,10 +8,10 @@ namespace NCronJob; /// /// Represents the builder for the NCronJob options. /// -public class NCronJobOptionBuilder : IJobStage +public class NCronJobOptionBuilder : IJobStage, IRuntimeJobBuilder { - private protected readonly IServiceCollection Services; - private protected readonly ConcurrencySettings Settings; + private readonly IServiceCollection services; + private readonly ConcurrencySettings settings; private readonly JobRegistry jobRegistry; internal NCronJobOptionBuilder( @@ -19,8 +19,8 @@ internal NCronJobOptionBuilder( ConcurrencySettings settings, JobRegistry jobRegistry) { - Services = services; - Settings = settings; + this.services = services; + this.settings = settings; this.jobRegistry = jobRegistry; } @@ -41,7 +41,7 @@ public IStartupStage AddJob(Action? options = null) where T : class, IJob { var builder = AddJobInternal(typeof(T), options); - return new StartupStage(Services, Settings, jobRegistry, builder); + return new StartupStage(services, settings, jobRegistry, builder); } /// @@ -60,7 +60,7 @@ public IStartupStage AddJob(Action? options = null) public IStartupStage AddJob(Type jobType, Action? options = null) { var builder = AddJobInternal(jobType, options); - return new StartupStage(Services, Settings, jobRegistry, builder); + return new StartupStage(services, settings, jobRegistry, builder); } /// @@ -103,10 +103,25 @@ public NCronJobOptionBuilder AddJob( /// public NCronJobOptionBuilder AddExceptionHandler() where TExceptionHandler : class, IExceptionHandler { - Services.AddSingleton(); + services.AddSingleton(); return this; } + IRuntimeJobBuilder IRuntimeJobBuilder.AddJob(Action? options) + { + AddJob(options); + return this; + } + + IRuntimeJobBuilder IRuntimeJobBuilder.AddJob(Type jobType, Action? options) + { + AddJob(jobType, options); + return this; + } + + IRuntimeJobBuilder IRuntimeJobBuilder.AddJob(Delegate jobDelegate, string cronExpression, TimeZoneInfo? timeZoneInfo, string? jobName) => + AddJob(jobDelegate, cronExpression, timeZoneInfo, jobName); + private void ValidateConcurrencySetting(object jobIdentifier) { var cachedJobAttributes = jobIdentifier switch @@ -117,11 +132,11 @@ private void ValidateConcurrencySetting(object jobIdentifier) }; var concurrencyAttribute = cachedJobAttributes.ConcurrencyPolicy; - if (concurrencyAttribute != null && concurrencyAttribute.MaxDegreeOfParallelism > Settings.MaxDegreeOfParallelism) + if (concurrencyAttribute != null && concurrencyAttribute.MaxDegreeOfParallelism > settings.MaxDegreeOfParallelism) { var name = jobIdentifier is Type type ? type.Name : ((MethodInfo)jobIdentifier).Name; throw new InvalidOperationException( - $"The MaxDegreeOfParallelism for {name} ({concurrencyAttribute.MaxDegreeOfParallelism}) cannot exceed the global limit ({Settings.MaxDegreeOfParallelism})."); + $"The MaxDegreeOfParallelism for {name} ({concurrencyAttribute.MaxDegreeOfParallelism}) cannot exceed the global limit ({settings.MaxDegreeOfParallelism})."); } } @@ -143,7 +158,7 @@ private JobOptionBuilder AddJobInternal(Type jobType, Action? var builder = new JobOptionBuilder(); options?.Invoke(builder); - Services.TryAddScoped(jobType); + services.TryAddScoped(jobType); var jobOptions = builder.GetJobOptions(); diff --git a/src/NCronJob/Registry/RuntimeJobRegistry.cs b/src/NCronJob/Registry/RuntimeJobRegistry.cs index 5a47312..e46615b 100644 --- a/src/NCronJob/Registry/RuntimeJobRegistry.cs +++ b/src/NCronJob/Registry/RuntimeJobRegistry.cs @@ -11,7 +11,7 @@ public interface IRuntimeJobRegistry /// /// Gives the ability to add a job. /// - void AddJob(Action jobBuilder); + void AddJob(Action jobBuilder); /// /// Removes the job with the given name. @@ -121,7 +121,7 @@ public RuntimeJobRegistry( } /// - public void AddJob(Action jobBuilder) + public void AddJob(Action jobBuilder) { var builder = new NCronJobOptionBuilder(services, concurrencySettings, jobRegistry); jobBuilder(builder);