mirror of https://github.com/abpframework/abp.git
16 changed files with 302 additions and 124 deletions
@ -0,0 +1,119 @@ |
|||
using System; |
|||
using System.Diagnostics; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Threading; |
|||
using Volo.Abp.Timing; |
|||
|
|||
namespace Volo.Abp.BackgroundJobs |
|||
{ |
|||
public class BackgroundJobExecuter : IBackgroundJobExecuter, ITransientDependency |
|||
{ |
|||
public ILogger<BackgroundJobExecuter> Logger { protected get; set; } |
|||
|
|||
protected IServiceProvider ServiceProvider { get; } |
|||
protected IClock Clock { get; } |
|||
protected IBackgroundJobSerializer Serializer { get; } |
|||
protected IBackgroundJobStore Store { get; } |
|||
protected BackgroundJobOptions Options { get; } |
|||
|
|||
public BackgroundJobExecuter( |
|||
IServiceProvider serviceProvider, |
|||
IClock clock, |
|||
IBackgroundJobSerializer serializer, |
|||
IBackgroundJobStore store, |
|||
IOptions<BackgroundJobOptions> options) |
|||
{ |
|||
ServiceProvider = serviceProvider; |
|||
Clock = clock; |
|||
Serializer = serializer; |
|||
Options = options.Value; |
|||
Store = store; |
|||
|
|||
Logger = NullLogger<BackgroundJobExecuter>.Instance; |
|||
} |
|||
|
|||
public void Execute(BackgroundJobInfo jobInfo) |
|||
{ |
|||
try |
|||
{ |
|||
jobInfo.TryCount++; |
|||
jobInfo.LastTryTime = Clock.Now; |
|||
|
|||
var jobType = Options.GetJobType(jobInfo.JobName); |
|||
|
|||
using (var scope = ServiceProvider.CreateScope()) |
|||
{ |
|||
var job = scope.ServiceProvider.GetService(jobType); |
|||
if (job == null) |
|||
{ |
|||
throw new AbpException("JobName is not registered: " + jobType); |
|||
} |
|||
|
|||
//TODO: Type check for the job object
|
|||
|
|||
var jobExecuteMethod = job.GetType().GetMethod("Execute"); |
|||
Debug.Assert(jobExecuteMethod != null, nameof(jobExecuteMethod) + " != null"); |
|||
var argsType = jobExecuteMethod.GetParameters()[0].ParameterType; |
|||
var argsObj = Serializer.Deserialize(jobInfo.JobArgs, argsType); |
|||
|
|||
try |
|||
{ |
|||
jobExecuteMethod.Invoke(job, new[] { argsObj }); |
|||
AsyncHelper.RunSync(() => Store.DeleteAsync(jobInfo)); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Logger.LogException(ex); |
|||
|
|||
var nextTryTime = jobInfo.CalculateNextTryTime(Clock); |
|||
if (nextTryTime.HasValue) |
|||
{ |
|||
jobInfo.NextTryTime = nextTryTime.Value; |
|||
} |
|||
else |
|||
{ |
|||
jobInfo.IsAbandoned = true; |
|||
} |
|||
|
|||
TryUpdate(jobInfo); |
|||
|
|||
var backgroundJobException = new BackgroundJobException( |
|||
"A background job execution is failed. See inner exception for details. See BackgroundJob property to get information on the background job.", |
|||
ex |
|||
) |
|||
{ |
|||
BackgroundJob = jobInfo, |
|||
JobObject = job |
|||
}; |
|||
|
|||
//TODO: Somehow trigger an event for the exception (may create an Volo.Abp.ExceptionHandling package)!
|
|||
} |
|||
} |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Logger.LogException(ex); |
|||
|
|||
jobInfo.IsAbandoned = true; |
|||
|
|||
TryUpdate(jobInfo); |
|||
} |
|||
} |
|||
|
|||
private void TryUpdate(BackgroundJobInfo jobInfo) |
|||
{ |
|||
try |
|||
{ |
|||
Store.UpdateAsync(jobInfo); |
|||
} |
|||
catch (Exception updateEx) |
|||
{ |
|||
Logger.LogException(updateEx); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
using System; |
|||
using System.Linq; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.BackgroundJobs |
|||
{ |
|||
public class BackgroundJobNameAttribute : Attribute, IBackgroundJobNameProvider |
|||
{ |
|||
public string Name { get; } |
|||
|
|||
public BackgroundJobNameAttribute([NotNull] string name) |
|||
{ |
|||
Name = Check.NotNullOrWhiteSpace(name, nameof(name)); |
|||
} |
|||
|
|||
public static string GetNameOrNull<TJobArgs>() |
|||
{ |
|||
return GetNameOrNull(typeof(TJobArgs)); |
|||
} |
|||
|
|||
public static string GetNameOrNull(Type jobArgsType) |
|||
{ |
|||
return jobArgsType |
|||
.GetCustomAttributes(true) |
|||
.OfType<IBackgroundJobNameProvider>() |
|||
.FirstOrDefault() |
|||
?.Name; |
|||
} |
|||
} |
|||
} |
|||
@ -1,12 +1,29 @@ |
|||
namespace Volo.Abp.BackgroundJobs |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.BackgroundJobs |
|||
{ |
|||
public class BackgroundJobOptions |
|||
{ |
|||
public Dictionary<string, Type> JobTypes { get; } |
|||
|
|||
public bool IsJobExecutionEnabled { get; set; } |
|||
|
|||
public BackgroundJobOptions() |
|||
{ |
|||
IsJobExecutionEnabled = true; |
|||
JobTypes = new Dictionary<string, Type>(); |
|||
} |
|||
|
|||
public Type GetJobType(string jobName) |
|||
{ |
|||
var jobType = JobTypes.GetOrDefault(jobName); |
|||
if (jobType == null) |
|||
{ |
|||
throw new AbpException("Undefined background job type for the job name: " + jobName); |
|||
} |
|||
|
|||
return jobType; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp.BackgroundJobs |
|||
{ |
|||
public interface IBackgroundJobExecuter |
|||
{ |
|||
void Execute(BackgroundJobInfo jobInfo); |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp.BackgroundJobs |
|||
{ |
|||
public interface IBackgroundJobNameProvider |
|||
{ |
|||
string Name { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,2 @@ |
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> |
|||
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp71</s:String></wpf:ResourceDictionary> |
|||
@ -0,0 +1,16 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.BackgroundJobs |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpBackgroundJobsModule) |
|||
)] |
|||
public class AbpBackgroundJobsTestModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddAssemblyOf<AbpBackgroundJobsTestModule>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
using System.Threading.Tasks; |
|||
using Shouldly; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.BackgroundJobs |
|||
{ |
|||
public class BackgroundJobManager_Tests : BackgroundJobsTestBase |
|||
{ |
|||
private readonly IBackgroundJobManager _backgroundJobManager; |
|||
private readonly IBackgroundJobStore _backgroundJobStore; |
|||
|
|||
public BackgroundJobManager_Tests() |
|||
{ |
|||
_backgroundJobManager = GetRequiredService<IBackgroundJobManager>(); |
|||
_backgroundJobStore = GetRequiredService<IBackgroundJobStore>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_Store_Jobs() |
|||
{ |
|||
var jobId = await _backgroundJobManager.EnqueueAsync(new MyJobArgs("42")); |
|||
jobId.ShouldNotBe(default); |
|||
(await _backgroundJobStore.FindAsync(jobId)).ShouldNotBeNull(); |
|||
} |
|||
|
|||
[BackgroundJobName("TestJobs.MyJob")] |
|||
private class MyJobArgs |
|||
{ |
|||
public string Value { get; set; } |
|||
|
|||
public MyJobArgs() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public MyJobArgs(string value) |
|||
{ |
|||
Value = value; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp.BackgroundJobs |
|||
{ |
|||
public abstract class BackgroundJobsTestBase : AbpIntegratedTest<AbpBackgroundJobsTestModule> |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -1,7 +0,0 @@ |
|||
namespace Volo.Abp.BackgroundJobs |
|||
{ |
|||
public class Class1 |
|||
{ |
|||
|
|||
} |
|||
} |
|||
Loading…
Reference in new issue