|
|
|
@ -5,8 +5,6 @@ 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 |
|
|
|
{ |
|
|
|
@ -15,120 +13,58 @@ namespace Volo.Abp.BackgroundJobs |
|
|
|
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 virtual void Execute(BackgroundJobInfo jobInfo) |
|
|
|
public virtual void Execute(JobExecutionContext context) |
|
|
|
{ |
|
|
|
//TODO: Refactor (split to multiple methods).
|
|
|
|
|
|
|
|
try |
|
|
|
var jobType = Options.GetJobType(context.JobName); |
|
|
|
|
|
|
|
using (var scope = ServiceProvider.CreateScope()) |
|
|
|
{ |
|
|
|
jobInfo.TryCount++; |
|
|
|
jobInfo.LastTryTime = Clock.Now; |
|
|
|
var job = scope.ServiceProvider.GetService(jobType); |
|
|
|
if (job == null) |
|
|
|
{ |
|
|
|
throw new AbpException("The job type is not registered to DI: " + jobType); |
|
|
|
} |
|
|
|
|
|
|
|
var jobType = Options.GetJobType(jobInfo.JobName); |
|
|
|
var jobExecuteMethod = job.GetType().GetMethod("Execute"); |
|
|
|
Debug.Assert(jobExecuteMethod != null, nameof(jobExecuteMethod) + " != null"); |
|
|
|
var argsType = jobExecuteMethod.GetParameters()[0].ParameterType; |
|
|
|
var argsObj = Serializer.Deserialize(context.JobArgs, argsType); |
|
|
|
|
|
|
|
using (var scope = ServiceProvider.CreateScope()) |
|
|
|
try |
|
|
|
{ |
|
|
|
var job = scope.ServiceProvider.GetService(jobType); |
|
|
|
if (job == null) |
|
|
|
{ |
|
|
|
throw new AbpException("The job type is not registered to DI: " + jobType); |
|
|
|
} |
|
|
|
jobExecuteMethod.Invoke(job, new[] { argsObj }); |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
context.Result = JobExecutionResult.Failed; |
|
|
|
|
|
|
|
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); |
|
|
|
Logger.LogException(ex); |
|
|
|
|
|
|
|
try |
|
|
|
//TODO: Somehow trigger an event for the exception (may create an Volo.Abp.ExceptionHandling package)!
|
|
|
|
var backgroundJobException = new BackgroundJobException("A background job execution is failed. See inner exception for details.", ex) |
|
|
|
{ |
|
|
|
jobExecuteMethod.Invoke(job, new[] { argsObj }); |
|
|
|
AsyncHelper.RunSync(() => Store.DeleteAsync(jobInfo.Id)); |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
Logger.LogException(ex); |
|
|
|
|
|
|
|
var nextTryTime = CalculateNextTryTime(jobInfo); |
|
|
|
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)!
|
|
|
|
} |
|
|
|
JobName = context.JobName, |
|
|
|
JobArgs = context.JobArgs |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
Logger.LogException(ex); |
|
|
|
|
|
|
|
jobInfo.IsAbandoned = true; |
|
|
|
|
|
|
|
TryUpdate(jobInfo); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
protected virtual void TryUpdate(BackgroundJobInfo jobInfo) |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
Store.UpdateAsync(jobInfo); |
|
|
|
} |
|
|
|
catch (Exception updateEx) |
|
|
|
{ |
|
|
|
Logger.LogException(updateEx); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
protected virtual DateTime? CalculateNextTryTime(BackgroundJobInfo jobInfo) //TODO: Move to another place to override easier
|
|
|
|
{ |
|
|
|
var nextWaitDuration = Options.DefaultFirstWaitDuration * (Math.Pow(Options.DefaultWaitFactor, jobInfo.TryCount - 1)); |
|
|
|
var nextTryDate = jobInfo.LastTryTime.HasValue |
|
|
|
? jobInfo.LastTryTime.Value.AddSeconds(nextWaitDuration) |
|
|
|
: Clock.Now.AddSeconds(nextWaitDuration); |
|
|
|
|
|
|
|
if (nextTryDate.Subtract(jobInfo.CreationTime).TotalSeconds > Options.DefaultTimeout) |
|
|
|
{ |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
return nextTryDate; |
|
|
|
} |
|
|
|
} |
|
|
|
} |