diff --git a/CHANGELOG.md b/CHANGELOG.md index ed23b8d0..f3819af1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ All notable changes to **NCronJob** will be documented in this file. The project - Expose typed version of `DisableJob()`. Added in [#151](https://github.com/NCronJob-Dev/NCronJob/issues/151), by [@nulltoken](https://github.com/nulltoken). - Expose typed version of `EnableJob()`. Added in [#151](https://github.com/NCronJob-Dev/NCronJob/issues/151), by [@nulltoken](https://github.com/nulltoken). +### Changed + +- Teach `IInstantJobRegistry` members to return the job correlation id. Changed in [#153](https://github.com/NCronJob-Dev/NCronJob/issues/153), by [@nulltoken](https://github.com/nulltoken). + ### Fixed - Make `RemoveJob()` and `RemoveJob(Type)` remove all jobs of the given type. Fixed in [#151](https://github.com/NCronJob-Dev/NCronJob/issues/151), by [@nulltoken](https://github.com/nulltoken). diff --git a/docs/features/instant-jobs.md b/docs/features/instant-jobs.md index aab92e7e..356db0af 100644 --- a/docs/features/instant-jobs.md +++ b/docs/features/instant-jobs.md @@ -104,3 +104,15 @@ app.MapPost("/send-email", (RequestDto dto, IInstantJobRegistry jobRegistry) => return TypedResults.Ok(); }); ``` + +## Instrumentation + +All members of the `IInstantJobRegistry` interface return the correlation id of the triggered job (See [*"Tracing requests of dependencies via `CorrelationId`"*](./model-dependencies.md#tracing-requests-of-dependencies-via-correlationid).). + +```csharp +Guid oneCorrelationId = jobRegistry.RunInstantJob(); + +Guid anotherCorrelationId = jobRegistry.RunScheduledJob(TimeSpan.FromMinutes(5)); + +[...] +``` diff --git a/src/NCronJob/Registry/IInstantJobRegistry.cs b/src/NCronJob/Registry/IInstantJobRegistry.cs index 40b2a0b9..87c4bb85 100644 --- a/src/NCronJob/Registry/IInstantJobRegistry.cs +++ b/src/NCronJob/Registry/IInstantJobRegistry.cs @@ -14,6 +14,7 @@ public interface IInstantJobRegistry /// An optional parameter that is passed down as the to the job. /// An optional token to cancel the job. /// + /// The job correlation id. /// /// This is a fire-and-forget process, the Job will be queued with high priority and run in the background. The contents of /// are not serialized and deserialized. It is the reference to the -object that gets passed in. @@ -24,7 +25,7 @@ public interface IInstantJobRegistry /// instantJobRegistry.RunInstantJob<MyJob>(new MyParameterObject { Foo = "Bar" }); /// /// - void RunInstantJob(object? parameter = null, CancellationToken token = default) + Guid RunInstantJob(object? parameter = null, CancellationToken token = default) where TJob : IJob; /// @@ -36,7 +37,8 @@ void RunInstantJob(object? parameter = null, CancellationToken token = def /// /// The delegate to execute. /// An optional token to cancel the job. - void RunInstantJob(Delegate jobDelegate, CancellationToken token = default); + /// The job correlation id. + Guid RunInstantJob(Delegate jobDelegate, CancellationToken token = default); /// /// Runs a job that will be executed after the given . @@ -44,7 +46,8 @@ void RunInstantJob(object? parameter = null, CancellationToken token = def /// The delay until the job will be executed. /// An optional parameter that is passed down as the to the job. /// An optional token to cancel the job. - void RunScheduledJob(TimeSpan delay, object? parameter = null, CancellationToken token = default) + /// The job correlation id. + Guid RunScheduledJob(TimeSpan delay, object? parameter = null, CancellationToken token = default) where TJob : IJob; /// @@ -53,7 +56,8 @@ void RunScheduledJob(TimeSpan delay, object? parameter = null, Cancellatio /// The starting point when the job will be executed. /// An optional parameter that is passed down as the to the job. /// An optional token to cancel the job. - void RunScheduledJob(DateTimeOffset startDate, object? parameter = null, CancellationToken token = default) + /// The job correlation id. + Guid RunScheduledJob(DateTimeOffset startDate, object? parameter = null, CancellationToken token = default) where TJob : IJob; /// @@ -62,11 +66,12 @@ void RunScheduledJob(DateTimeOffset startDate, object? parameter = null, C /// The delegate to execute. /// The delay until the job will be executed. /// An optional token to cancel the job. + /// The job correlation id. /// /// The delegate supports, like , that services can be retrieved dynamically. /// Also, the can be retrieved in this way. /// - void RunScheduledJob(Delegate jobDelegate, TimeSpan delay, CancellationToken token = default); + Guid RunScheduledJob(Delegate jobDelegate, TimeSpan delay, CancellationToken token = default); /// /// Runs a job that will be executed at the given . @@ -74,11 +79,12 @@ void RunScheduledJob(DateTimeOffset startDate, object? parameter = null, C /// The delegate to execute. /// The starting point when the job will be executed. /// An optional token to cancel the job. + /// The job correlation id. /// /// The delegate supports, like , that services can be retrieved dynamically. /// Also, the can be retrieved in this way. /// - void RunScheduledJob(Delegate jobDelegate, DateTimeOffset startDate, CancellationToken token = default); + Guid RunScheduledJob(Delegate jobDelegate, DateTimeOffset startDate, CancellationToken token = default); /// /// Runs a job that will be executed after the given . The job will not be queued into the JobQueue, but executed directly. @@ -86,11 +92,12 @@ void RunScheduledJob(DateTimeOffset startDate, object? parameter = null, C /// The delegate to execute. /// The delay until the job will be executed. /// An optional token to cancel the job. + /// The job correlation id. /// /// The delegate supports, like , that services can be retrieved dynamically. /// Also, the can be retrieved in this way. /// - void ForceRunScheduledJob(Delegate jobDelegate, TimeSpan delay, CancellationToken token = default); + Guid ForceRunScheduledJob(Delegate jobDelegate, TimeSpan delay, CancellationToken token = default); /// /// Runs a job that will be executed at the given . The job will not be queued into the JobQueue, but executed directly. @@ -98,11 +105,12 @@ void RunScheduledJob(DateTimeOffset startDate, object? parameter = null, C /// The delegate to execute. /// The starting point when the job will be executed. /// An optional token to cancel the job. + /// The job correlation id. /// /// The delegate supports, like , that services can be retrieved dynamically. /// Also, the can be retrieved in this way. /// - void ForceRunScheduledJob(Delegate jobDelegate, DateTimeOffset startDate, CancellationToken token = default); + Guid ForceRunScheduledJob(Delegate jobDelegate, DateTimeOffset startDate, CancellationToken token = default); /// /// Runs a job that will be executed after the given . The job will not be queued into the JobQueue, but executed directly. @@ -111,7 +119,8 @@ void RunScheduledJob(DateTimeOffset startDate, object? parameter = null, C /// The delay until the job will be executed. /// An optional parameter that is passed down as the to the job. /// An optional token to cancel the job. - void ForceRunScheduledJob(TimeSpan delay, object? parameter = null, CancellationToken token = default) + /// The job correlation id. + Guid ForceRunScheduledJob(TimeSpan delay, object? parameter = null, CancellationToken token = default) where TJob : IJob; /// @@ -119,6 +128,7 @@ void ForceRunScheduledJob(TimeSpan delay, object? parameter = null, Cancel /// An optional parameter that is passed down as the to the job. /// An optional token to cancel the job. /// + /// The job correlation id. /// /// This is a fire-and-forget process, the Job will be run immediately in the background. The contents of /// are not serialized and deserialized. It is the reference to the -object that gets passed in. @@ -129,7 +139,7 @@ void ForceRunScheduledJob(TimeSpan delay, object? parameter = null, Cancel /// instantJobRegistry.RunInstantJob<MyJob>(new MyParameterObject { Foo = "Bar" }); /// /// - void ForceRunInstantJob(object? parameter = null, CancellationToken token = default) + Guid ForceRunInstantJob(object? parameter = null, CancellationToken token = default) where TJob : IJob; /// @@ -141,8 +151,8 @@ void ForceRunInstantJob(object? parameter = null, CancellationToken token /// /// The delegate to execute. /// An optional token to cancel the job. - void ForceRunInstantJob(Delegate jobDelegate, CancellationToken token = default); - + /// The job correlation id. + Guid ForceRunInstantJob(Delegate jobDelegate, CancellationToken token = default); } internal sealed partial class InstantJobRegistry : IInstantJobRegistry @@ -168,71 +178,71 @@ public InstantJobRegistry( } /// - public void RunInstantJob(object? parameter = null, CancellationToken token = default) + public Guid RunInstantJob(object? parameter = null, CancellationToken token = default) where TJob : IJob => RunScheduledJob(TimeSpan.Zero, parameter, token); /// - public void RunInstantJob(Delegate jobDelegate, CancellationToken token = default) => RunScheduledJob(jobDelegate, TimeSpan.Zero, token); + public Guid RunInstantJob(Delegate jobDelegate, CancellationToken token = default) => RunScheduledJob(jobDelegate, TimeSpan.Zero, token); /// - public void RunScheduledJob(TimeSpan delay, object? parameter = null, CancellationToken token = default) + public Guid RunScheduledJob(TimeSpan delay, object? parameter = null, CancellationToken token = default) where TJob : IJob { var utcNow = timeProvider.GetUtcNow(); - RunJob(utcNow + delay, parameter, false, token); + return RunJob(utcNow + delay, parameter, false, token); } /// - public void RunScheduledJob(DateTimeOffset startDate, object? parameter = null, CancellationToken token = default) + public Guid RunScheduledJob(DateTimeOffset startDate, object? parameter = null, CancellationToken token = default) where TJob : IJob => RunJob(startDate, parameter, false, token); /// - public void RunScheduledJob(Delegate jobDelegate, TimeSpan delay, CancellationToken token = default) + public Guid RunScheduledJob(Delegate jobDelegate, TimeSpan delay, CancellationToken token = default) { var utcNow = timeProvider.GetUtcNow(); - RunScheduledJob(jobDelegate, utcNow + delay, token); + return RunScheduledJob(jobDelegate, utcNow + delay, token); } /// - public void RunScheduledJob(Delegate jobDelegate, DateTimeOffset startDate, CancellationToken token = default) => + public Guid RunScheduledJob(Delegate jobDelegate, DateTimeOffset startDate, CancellationToken token = default) => RunDelegateJob(jobDelegate, startDate, false, token); /// - public void ForceRunScheduledJob(TimeSpan delay, object? parameter = null, CancellationToken token = default) + public Guid ForceRunScheduledJob(TimeSpan delay, object? parameter = null, CancellationToken token = default) where TJob : IJob { var utcNow = timeProvider.GetUtcNow(); - RunJob(utcNow + delay, parameter, true, token); + return RunJob(utcNow + delay, parameter, true, token); } /// - public void ForceRunScheduledJob(Delegate jobDelegate, TimeSpan delay, CancellationToken token = default) + public Guid ForceRunScheduledJob(Delegate jobDelegate, TimeSpan delay, CancellationToken token = default) { var utcNow = timeProvider.GetUtcNow(); - ForceRunScheduledJob(jobDelegate, utcNow + delay, token); + return ForceRunScheduledJob(jobDelegate, utcNow + delay, token); } /// - public void ForceRunScheduledJob(Delegate jobDelegate, DateTimeOffset startDate, CancellationToken token = default) => + public Guid ForceRunScheduledJob(Delegate jobDelegate, DateTimeOffset startDate, CancellationToken token = default) => RunDelegateJob(jobDelegate, startDate, true, token); /// - public void ForceRunInstantJob(Delegate jobDelegate, CancellationToken token = default) => + public Guid ForceRunInstantJob(Delegate jobDelegate, CancellationToken token = default) => ForceRunScheduledJob(jobDelegate, TimeSpan.Zero, token); /// - public void ForceRunInstantJob(object? parameter = null, CancellationToken token = default) + public Guid ForceRunInstantJob(object? parameter = null, CancellationToken token = default) where TJob : IJob => ForceRunScheduledJob(TimeSpan.Zero, parameter, token); - private void RunDelegateJob(Delegate jobDelegate, DateTimeOffset startDate, bool forceExecution = false, CancellationToken token = default) + private Guid RunDelegateJob(Delegate jobDelegate, DateTimeOffset startDate, bool forceExecution = false, CancellationToken token = default) { var definition = jobRegistry.AddDynamicJob(jobDelegate); - RunInternal(definition, null, startDate, forceExecution, token); + return RunInternal(definition, null, startDate, forceExecution, token); } - private void RunJob(DateTimeOffset startDate, object? parameter = null, bool forceExecution = false, CancellationToken token = default) + private Guid RunJob(DateTimeOffset startDate, object? parameter = null, bool forceExecution = false, CancellationToken token = default) where TJob : IJob { using (logger.BeginScope("Triggering RunScheduledJob:")) @@ -247,11 +257,11 @@ private void RunJob(DateTimeOffset startDate, object? parameter = null, bo token.Register(() => LogCancellationRequested(parameter)); - RunInternal(jobDefinition, parameter, startDate, forceExecution, token); + return RunInternal(jobDefinition, parameter, startDate, forceExecution, token); } } - private void RunInternal( + private Guid RunInternal( JobDefinition jobDefinition, object? parameter, DateTimeOffset startDate, @@ -273,6 +283,8 @@ private void RunInternal( jobQueue.EnqueueForDirectExecution(run, startDate); jobQueueManager.SignalJobQueue(run.JobDefinition.JobFullName); } + + return run.CorrelationId; } [LoggerMessage(LogLevel.Warning, "Job {JobName} cancelled by request.")] diff --git a/tests/NCronJob.Tests/RunDependentJobTests.cs b/tests/NCronJob.Tests/RunDependentJobTests.cs index d2e03d2a..a50695d2 100644 --- a/tests/NCronJob.Tests/RunDependentJobTests.cs +++ b/tests/NCronJob.Tests/RunDependentJobTests.cs @@ -84,12 +84,13 @@ public async Task CorrelationIdIsSharedByJobsAndTheirDependencies() var provider = CreateServiceProvider(); await provider.GetRequiredService().StartAsync(CancellationToken); - provider.GetRequiredService().ForceRunInstantJob(token: CancellationToken); + var correlationId = provider.GetRequiredService().ForceRunInstantJob(token: CancellationToken); await CommunicationChannel.Reader.ReadAsync(CancellationToken); var storage = provider.GetRequiredService(); storage.Guids.Count.ShouldBe(2); storage.Guids.Distinct().Count().ShouldBe(1); + storage.Guids.First().ShouldBe(correlationId); } [Fact]