diff --git a/docs/en/Background-Jobs.md b/docs/en/Background-Jobs.md index 84e746f73d..c6e19fb48a 100644 --- a/docs/en/Background-Jobs.md +++ b/docs/en/Background-Jobs.md @@ -75,6 +75,42 @@ This job simply uses `IEmailSender` to send emails (see [email sending document] A background job should not hide exceptions. If it throws an exception, the background job is automatically re-tried after a calculated waiting time. Hide exceptions only if you don't want to re-run the background job for the current argument. +#### Cancelling Background Jobs + +If your background task is cancellable, then you can use the standard [Cancellation Token](Cancellation-Token-Provider.md) system to obtain a `CancellationToken` to cancel your job when requested. See the following example that uses the `ICancellationTokenProvider` to obtain the cancellation token: + +```csharp +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; + +namespace MyProject +{ + public class LongRunningJob : AsyncBackgroundJob, ITransientDependency + { + private readonly ICancellationTokenProvider _cancellationTokenProvider; + + public LongRunningJob(ICancellationTokenProvider cancellationTokenProvider) + { + _cancellationTokenProvider = cancellationTokenProvider; + } + + public override async Task ExecuteAsync(LongRunningJobArgs args) + { + foreach (var id in args.Ids) + { + _cancellationTokenProvider.Token.ThrowIfCancellationRequested(); + await ProcessAsync(id); // code omitted for brevity + } + } + } +} +``` + +> A cancellation operation might be needed if the application is shutting down and we don't want to block the application in the background job. This example throws an exception if the cancellation is requested. So, the job will be retried the next time the application starts. If you don't want that, just return from the `ExecuteAsync` method without throwing any exception (you can simply check the `_cancellationTokenProvider.Token.IsCancellationRequested` property). + #### Job Name Each background job has a name. Job names are used in several places. For example, RabbitMQ provider uses job names to determine the RabbitMQ Queue names. diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AsyncBackgroundJob.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AsyncBackgroundJob.cs index 4cf298f712..aa6cad070a 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AsyncBackgroundJob.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AsyncBackgroundJob.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -6,7 +7,7 @@ namespace Volo.Abp.BackgroundJobs; public abstract class AsyncBackgroundJob : IAsyncBackgroundJob { - //TODO: Add UOW, Localization and other useful properties..? + //TODO: Add UOW, Localization, CancellationTokenProvider and other useful properties..? public ILogger> Logger { get; set; } diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJob.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJob.cs index 57beeb77b5..b1770942fe 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJob.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJob.cs @@ -1,3 +1,4 @@ +using System.Threading; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -5,7 +6,7 @@ namespace Volo.Abp.BackgroundJobs; public abstract class BackgroundJob : IBackgroundJob { - //TODO: Add UOW, Localization and other useful properties..? + //TODO: Add UOW, Localization, CancellationTokenProvider and other useful properties..? public ILogger> Logger { get; set; } diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobExecuter.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobExecuter.cs index 7a6f54fbd7..7798a8d9a6 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobExecuter.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobExecuter.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.DependencyInjection; using Volo.Abp.ExceptionHandling; using Volo.Abp.MultiTenancy; +using Volo.Abp.Threading; namespace Volo.Abp.BackgroundJobs; @@ -46,13 +47,19 @@ public class BackgroundJobExecuter : IBackgroundJobExecuter, ITransientDependenc { using(CurrentTenant.Change(GetJobArgsTenantId(context.JobArgs))) { - if (jobExecuteMethod.Name == nameof(IAsyncBackgroundJob.ExecuteAsync)) - { - await ((Task)jobExecuteMethod.Invoke(job, new[] { context.JobArgs })); - } - else + var cancellationTokenProvider = + context.ServiceProvider.GetRequiredService(); + + using (cancellationTokenProvider.Use(context.CancellationToken)) { - jobExecuteMethod.Invoke(job, new[] { context.JobArgs }); + if (jobExecuteMethod.Name == nameof(IAsyncBackgroundJob.ExecuteAsync)) + { + await ((Task)jobExecuteMethod.Invoke(job, new[] { context.JobArgs })); + } + else + { + jobExecuteMethod.Invoke(job, new[] { context.JobArgs }); + } } } diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs index dc39b1bd0f..022067d3ed 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; namespace Volo.Abp.BackgroundJobs; diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs index 140db1e72a..8c8c17ca93 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.BackgroundJobs; +using System.Threading; + +namespace Volo.Abp.BackgroundJobs; /// /// Defines interface of a background job. diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/JobExecutionContext.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/JobExecutionContext.cs index a5de60d298..ae7e098070 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/JobExecutionContext.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/JobExecutionContext.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using Volo.Abp.DependencyInjection; namespace Volo.Abp.BackgroundJobs; @@ -11,10 +12,17 @@ public class JobExecutionContext : IServiceProviderAccessor public object JobArgs { get; } - public JobExecutionContext(IServiceProvider serviceProvider, Type jobType, object jobArgs) + public CancellationToken CancellationToken { get; } + + public JobExecutionContext( + IServiceProvider serviceProvider, + Type jobType, + object jobArgs, + CancellationToken cancellationToken = default) { ServiceProvider = serviceProvider; JobType = jobType; JobArgs = jobArgs; + CancellationToken = cancellationToken; } } 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 2583ada9fc..a94426adad 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 @@ -12,22 +12,22 @@ namespace Volo.Abp.BackgroundJobs.Hangfire; public class HangfireBackgroundJobManager : IBackgroundJobManager, ITransientDependency { protected AbpBackgroundJobOptions Options { get; } - + public HangfireBackgroundJobManager(IOptions options) { Options = options.Value; } - + public virtual Task EnqueueAsync(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, TimeSpan? delay = null) { return Task.FromResult(delay.HasValue ? BackgroundJob.Schedule>( - adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)),args), + adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)), args, default), delay.Value ) : BackgroundJob.Enqueue>( - adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)) ,args) + adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)), args, default) )); } diff --git a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs index 7ba0cd7db4..58d2863618 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using Hangfire; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -21,8 +22,8 @@ public class HangfireJobExecutionAdapter Options = options.Value; } - [Queue("{0}")] - public async Task ExecuteAsync(string queue, TArgs args) + [Queue("{0}")] + public async Task ExecuteAsync(string queue, TArgs args, CancellationToken cancellationToken = default) { if (!Options.IsJobExecutionEnabled) { @@ -38,7 +39,7 @@ public class HangfireJobExecutionAdapter using (var scope = ServiceScopeFactory.CreateScope()) { var jobType = Options.GetJob(typeof(TArgs)).JobType; - var context = new JobExecutionContext(scope.ServiceProvider, jobType, args); + var context = new JobExecutionContext(scope.ServiceProvider, jobType, args, cancellationToken: cancellationToken); await JobExecuter.ExecuteAsync(context); } } diff --git a/framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzJobExecutionAdapter.cs b/framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzJobExecutionAdapter.cs index 3127cc5910..588e844153 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzJobExecutionAdapter.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzJobExecutionAdapter.cs @@ -40,7 +40,7 @@ public class QuartzJobExecutionAdapter : IJob { var args = JsonSerializer.Deserialize(context.JobDetail.JobDataMap.GetString(nameof(TArgs))); var jobType = Options.GetJob(typeof(TArgs)).JobType; - var jobContext = new JobExecutionContext(scope.ServiceProvider, jobType, args); + var jobContext = new JobExecutionContext(scope.ServiceProvider, jobType, args, cancellationToken: context.CancellationToken); try { await JobExecuter.ExecuteAsync(jobContext); diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs index 8de0a5ff6e..4aeaf59885 100644 --- a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs +++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs @@ -68,7 +68,8 @@ public class BackgroundJobWorker : AsyncPeriodicBackgroundWorkerBase, IBackgroun var context = new JobExecutionContext( workerContext.ServiceProvider, jobConfiguration.JobType, - jobArgs); + jobArgs, + workerContext.CancellationToken); try { diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJob.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJob.cs index 881a6437d9..9a70469df8 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJob.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJob.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.BackgroundJobs; using Volo.Abp.DependencyInjection; diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobExecuter_Tests.cs b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobExecuter_Tests.cs index 42fe0da502..db7b5f5cc8 100644 --- a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobExecuter_Tests.cs +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobExecuter_Tests.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using Shouldly; using Xunit; @@ -59,7 +60,7 @@ public class BackgroundJobExecuter_Tests : BackgroundJobsTestBase jobObject.ExecutedValues.ShouldContain("42"); } - + [Fact] public async Task Should_Change_TenantId_If_EventData_Is_MultiTenant() { @@ -77,7 +78,7 @@ public class BackgroundJobExecuter_Tests : BackgroundJobsTestBase new MyJobArgs("42", tenantId) ) ); - + await _backgroundJobExecuter.ExecuteAsync( new JobExecutionContext( ServiceProvider, @@ -91,4 +92,48 @@ public class BackgroundJobExecuter_Tests : BackgroundJobsTestBase jobObject.TenantId.ShouldBe(tenantId); asyncJobObject.TenantId.ShouldBe(tenantId); } + + [Fact] + public async Task Should_Cancel_Job() + { + //Arrange + var cts = new CancellationTokenSource(); + cts.Cancel(); + + var jobObject = GetRequiredService(); + jobObject.ExecutedValues.ShouldBeEmpty(); + + //Act + await _backgroundJobExecuter.ExecuteAsync( + new JobExecutionContext( + ServiceProvider, + typeof(MyJob), + new MyJobArgs("42"), + cts.Token + ) + ); + + //Assert + jobObject.Canceled.ShouldBeTrue(); + + //Arrange + var asyncCts = new CancellationTokenSource(); + asyncCts.Cancel(); + + var asyncJobObject = GetRequiredService(); + asyncJobObject.ExecutedValues.ShouldBeEmpty(); + + //Act + await _backgroundJobExecuter.ExecuteAsync( + new JobExecutionContext( + ServiceProvider, + typeof(MyAsyncJob), + new MyAsyncJobArgs("42"), + asyncCts.Token + ) + ); + + //Assert + asyncJobObject.Canceled.ShouldBeTrue(); + } } diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJob.cs b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJob.cs index 79c5ea887a..d738b36130 100644 --- a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJob.cs +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJob.cs @@ -1,26 +1,39 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; +using Volo.Abp.Threading; namespace Volo.Abp.BackgroundJobs; public class MyAsyncJob : AsyncBackgroundJob, ISingletonDependency { public List ExecutedValues { get; } = new List(); - + public Guid? TenantId { get; set; } - + private readonly ICurrentTenant _currentTenant; + private readonly ICancellationTokenProvider _cancellationTokenProvider; - public MyAsyncJob(ICurrentTenant currentTenant) + public bool Canceled { get; set; } + + public MyAsyncJob( + ICurrentTenant currentTenant, + ICancellationTokenProvider cancellationTokenProvider) { _currentTenant = currentTenant; + _cancellationTokenProvider = cancellationTokenProvider; } public override Task ExecuteAsync(MyAsyncJobArgs args) { + if (_cancellationTokenProvider.Token.IsCancellationRequested) + { + Canceled = true; + } + ExecutedValues.Add(args.Value); TenantId = _currentTenant.Id; return Task.CompletedTask; diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyJob.cs b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyJob.cs index 3b01ec05d1..1f9658162d 100644 --- a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyJob.cs +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyJob.cs @@ -1,25 +1,38 @@ using System; using System.Collections.Generic; +using System.Threading; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; +using Volo.Abp.Threading; namespace Volo.Abp.BackgroundJobs; public class MyJob : BackgroundJob, ISingletonDependency { public List ExecutedValues { get; } = new List(); - + public Guid? TenantId { get; set; } private readonly ICurrentTenant _currentTenant; - - public MyJob(ICurrentTenant currentTenant) + private readonly ICancellationTokenProvider _cancellationTokenProvider; + + public bool Canceled { get; set; } + + public MyJob( + ICurrentTenant currentTenant, + ICancellationTokenProvider cancellationTokenProvider) { _currentTenant = currentTenant; + _cancellationTokenProvider = cancellationTokenProvider; } public override void Execute(MyJobArgs args) { + if (_cancellationTokenProvider.Token.IsCancellationRequested) + { + Canceled = true; + } + ExecutedValues.Add(args.Value); TenantId = _currentTenant.Id; } diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Program.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Program.cs index 5f2c23ceb4..244063d37f 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Program.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Program.cs @@ -1,23 +1,40 @@ using System; +using System.Threading; +using System.Threading.Tasks; +using Hangfire; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs; +using Volo.Abp.Threading; namespace Volo.Abp.BackgroundJobs.DemoApp.HangFire; class Program { - static void Main(string[] args) + async static Task Main(string[] args) { - using (var application = AbpApplicationFactory.Create(options => + using (var application = await AbpApplicationFactory.CreateAsync(options => + { + options.UseAutofac(); + })) { - options.UseAutofac(); - })) - { - application.Initialize(); + await application.InitializeAsync(); + + await CancelableBackgroundJobAsync(application.ServiceProvider); Console.WriteLine("Started: " + typeof(Program).Namespace); Console.WriteLine("Press ENTER to stop the application..!"); Console.ReadLine(); - application.Shutdown(); + await application.ShutdownAsync(); } } + + private async static Task CancelableBackgroundJobAsync(IServiceProvider serviceProvider) + { + var backgroundJobManager = serviceProvider.GetRequiredService(); + var jobId = await backgroundJobManager.EnqueueAsync(new LongRunningJobArgs { Value = "test-1" }); + await backgroundJobManager.EnqueueAsync(new LongRunningJobArgs { Value = "test-2" }); + Thread.Sleep(1000); + BackgroundJob.Delete(jobId); + } } diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Quartz/Program.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Quartz/Program.cs index 1ececcd621..eebe5fa279 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Quartz/Program.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Quartz/Program.cs @@ -1,23 +1,41 @@ using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Quartz; +using Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs; +using Volo.Abp.Threading; namespace Volo.Abp.BackgroundJobs.DemoApp.Quartz; class Program { - static void Main(string[] args) + async static Task Main(string[] args) { - using (var application = AbpApplicationFactory.Create(options => + using (var application = await AbpApplicationFactory.CreateAsync(options => { options.UseAutofac(); })) { - application.Initialize(); + await application.InitializeAsync(); + + await CancelableBackgroundJobAsync(application.ServiceProvider); Console.WriteLine("Started: " + typeof(Program).Namespace); Console.WriteLine("Press ENTER to stop the application..!"); Console.ReadLine(); - application.Shutdown(); + await application.ShutdownAsync(); } } + + private async static Task CancelableBackgroundJobAsync(IServiceProvider serviceProvider) + { + var backgroundJobManager = serviceProvider.GetRequiredService(); + var jobId = await backgroundJobManager.EnqueueAsync(new LongRunningJobArgs {Value = "test-1"}); + await backgroundJobManager.EnqueueAsync(new LongRunningJobArgs { Value = "test-2" }); + Thread.Sleep(1000); + var scheduler = serviceProvider.GetRequiredService(); + await scheduler.Interrupt(new JobKey(jobId.Split('.')[1],jobId.Split('.')[0])); + } } diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.RabbitMq/Program.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.RabbitMq/Program.cs index 5d04169c15..a07a0498f9 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.RabbitMq/Program.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.RabbitMq/Program.cs @@ -1,23 +1,24 @@ using System; +using System.Threading.Tasks; namespace Volo.Abp.BackgroundJobs.DemoApp.RabbitMq; class Program { - static void Main(string[] args) + async static Task Main(string[] args) { - using (var application = AbpApplicationFactory.Create(options => + using (var application = await AbpApplicationFactory.CreateAsync(options => { options.UseAutofac(); })) { - application.Initialize(); + await application.InitializeAsync(); Console.WriteLine("Started: " + typeof(Program).Namespace); Console.WriteLine("Press ENTER to stop the application..!"); Console.ReadLine(); - application.Shutdown(); + await application.ShutdownAsync(); } } } diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJob.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJob.cs new file mode 100644 index 0000000000..9a57331fff --- /dev/null +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJob.cs @@ -0,0 +1,49 @@ +using System; +using System.Threading; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; + +namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs +{ + public class LongRunningJob : BackgroundJob, ITransientDependency + { + private readonly ICancellationTokenProvider _cancellationTokenProvider; + + public LongRunningJob(ICancellationTokenProvider cancellationTokenProvider) + { + _cancellationTokenProvider = cancellationTokenProvider; + } + + public override void Execute(LongRunningJobArgs args) + { + lock (Console.Out) + { + var oldColor = Console.ForegroundColor; + try + { + Console.WriteLine($"Long running {args.Value} start: {DateTime.Now}"); + + for (var i = 1; i <= 10; i++) + { + _cancellationTokenProvider.Token.ThrowIfCancellationRequested(); + + Thread.Sleep(1000); + Console.WriteLine($"{args.Value} step-{i} done: {DateTime.Now}"); + } + + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine($"Long running {args.Value} completed: {DateTime.Now}"); + } + catch (OperationCanceledException) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"Long running {args.Value} cancelled!!!"); + } + finally + { + Console.ForegroundColor = oldColor; + } + } + } + } +} \ No newline at end of file diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJobArgs.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJobArgs.cs new file mode 100644 index 0000000000..fabba0fa57 --- /dev/null +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJobArgs.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs +{ + [BackgroundJobName("LongJob")] + public class LongRunningJobArgs + { + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleGreenJob.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleGreenJob.cs index e065e409e5..5e5c00a97d 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleGreenJob.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleGreenJob.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using Volo.Abp.DependencyInjection; namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleYellowJob.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleYellowJob.cs index a610b6e75a..dbeae26552 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleYellowJob.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleYellowJob.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using Volo.Abp.DependencyInjection; namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/DemoAppModule.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/DemoAppModule.cs index a909fb476e..976705b07d 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/DemoAppModule.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/DemoAppModule.cs @@ -1,4 +1,5 @@ -using Volo.Abp.Autofac; +using System.Threading.Tasks; +using Volo.Abp.Autofac; using Volo.Abp.BackgroundJobs.DemoApp.Shared; using Volo.Abp.BackgroundJobs.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; @@ -27,19 +28,21 @@ public class DemoAppModule : AbpModule Configure(options => { - //Configure for fast running - options.JobPollPeriod = 1000; + //Configure for fast running + options.JobPollPeriod = 1000; options.DefaultFirstWaitDuration = 1; options.DefaultWaitFactor = 1; }); } - public override void OnApplicationInitialization(ApplicationInitializationContext context) + public override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) { //TODO: Configure console logging //context // .ServiceProvider // .GetRequiredService() // .AddConsole(LogLevel.Debug); + + return Task.CompletedTask; } } diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Program.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Program.cs index f895e7adbb..f8fa05863d 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Program.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Program.cs @@ -1,23 +1,23 @@ using System; - +using System.Threading.Tasks; namespace Volo.Abp.BackgroundJobs.DemoApp; class Program { - static void Main(string[] args) + async static Task Main(string[] args) { - using (var application = AbpApplicationFactory.Create(options => + using (var application = await AbpApplicationFactory.CreateAsync(options => { options.UseAutofac(); })) { - application.Initialize(); + await application.InitializeAsync(); Console.WriteLine("Started: " + typeof(Program).Namespace); Console.WriteLine("Press ENTER to stop the application..!"); Console.ReadLine(); - application.Shutdown(); + await application.ShutdownAsync(); } } }