mirror of https://github.com/abpframework/abp.git
29 changed files with 363 additions and 91 deletions
@ -0,0 +1,19 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Autofac; |
||||
|
using Volo.Abp.BackgroundJobs.EntityFrameworkCore; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace Volo.Abp.BackgroundJobs.DemoApp |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(BackgroundJobsEntityFrameworkCoreModule), |
||||
|
typeof(AbpAutofacModule) |
||||
|
)] |
||||
|
public class DemoAppModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddAssemblyOf<DemoAppModule>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
namespace Volo.Abp.BackgroundJobs |
||||
|
{ |
||||
|
public static class BackgroundJobRecordConsts |
||||
|
{ |
||||
|
public const int MaxJobNameLength = 128; |
||||
|
|
||||
|
public const int MaxJobArgsLength = 1024 * 1024; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Domain.Entities; |
||||
|
|
||||
|
namespace Volo.Abp.BackgroundJobs |
||||
|
{ |
||||
|
public class BackgroundJobRecord : AggregateRoot<Guid>, IHasCreationTime |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Type of the job.
|
||||
|
/// It's AssemblyQualifiedName of job type.
|
||||
|
/// </summary>
|
||||
|
public virtual string JobName { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Job arguments as JSON string.
|
||||
|
/// </summary>
|
||||
|
public virtual string JobArgs { get; set; } //TODO: Consider to conver to byte[]
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Try count of this job.
|
||||
|
/// A job is re-tried if it fails.
|
||||
|
/// </summary>
|
||||
|
public virtual short TryCount { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Creation time of this job.
|
||||
|
/// </summary>
|
||||
|
public virtual DateTime CreationTime { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Next try time of this job.
|
||||
|
/// </summary>
|
||||
|
public virtual DateTime NextTryTime { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Last try time of this job.
|
||||
|
/// </summary>
|
||||
|
public virtual DateTime? LastTryTime { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This is true if this job is continously failed and will not be executed again.
|
||||
|
/// </summary>
|
||||
|
public virtual bool IsAbandoned { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Priority of this job.
|
||||
|
/// </summary>
|
||||
|
public virtual BackgroundJobPriority Priority { get; set; } |
||||
|
|
||||
|
public BackgroundJobRecord() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,55 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.ObjectMapping; |
||||
|
|
||||
|
namespace Volo.Abp.BackgroundJobs |
||||
|
{ |
||||
|
public class BackgroundJobStore : IBackgroundJobStore, ITransientDependency |
||||
|
{ |
||||
|
protected IBackgroundJobRepository BackgroundJobRepository { get; } |
||||
|
protected IObjectMapper ObjectMapper { get; } |
||||
|
|
||||
|
public BackgroundJobStore( |
||||
|
IBackgroundJobRepository backgroundJobRepository, |
||||
|
IObjectMapper objectMapper) |
||||
|
{ |
||||
|
ObjectMapper = objectMapper; |
||||
|
BackgroundJobRepository = backgroundJobRepository; |
||||
|
} |
||||
|
|
||||
|
public async Task<BackgroundJobInfo> FindAsync(Guid jobId) |
||||
|
{ |
||||
|
return ObjectMapper.Map<BackgroundJobRecord, BackgroundJobInfo>( |
||||
|
await BackgroundJobRepository.FindAsync(jobId) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public async Task InsertAsync(BackgroundJobInfo jobInfo) |
||||
|
{ |
||||
|
await BackgroundJobRepository.InsertAsync( |
||||
|
ObjectMapper.Map<BackgroundJobInfo, BackgroundJobRecord>(jobInfo) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public async Task<List<BackgroundJobInfo>> GetWaitingJobsAsync(int maxResultCount) |
||||
|
{ |
||||
|
return ObjectMapper.Map<List<BackgroundJobRecord>, List<BackgroundJobInfo>>( |
||||
|
await BackgroundJobRepository.GetWaitingListAsync(maxResultCount) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public async Task DeleteAsync(Guid jobId) |
||||
|
{ |
||||
|
await BackgroundJobRepository.DeleteAsync(jobId); |
||||
|
} |
||||
|
|
||||
|
public async Task UpdateAsync(BackgroundJobInfo jobInfo) |
||||
|
{ |
||||
|
await BackgroundJobRepository.UpdateAsync( |
||||
|
ObjectMapper.Map<BackgroundJobInfo, BackgroundJobRecord>(jobInfo) |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using AutoMapper; |
||||
|
|
||||
|
namespace Volo.Abp.BackgroundJobs |
||||
|
{ |
||||
|
public class BackgroundJobsDomainAutoMapperProfile : Profile |
||||
|
{ |
||||
|
public BackgroundJobsDomainAutoMapperProfile() |
||||
|
{ |
||||
|
CreateMap<BackgroundJobInfo, BackgroundJobRecord>() |
||||
|
.ReverseMap(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace Volo.Abp.BackgroundJobs |
||||
|
{ |
||||
|
public interface IBackgroundJobRepository : IBasicRepository<BackgroundJobRecord, Guid> |
||||
|
{ |
||||
|
Task<List<BackgroundJobRecord>> GetWaitingListAsync(int maxResultCount); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
using Volo.Abp.Timing; |
||||
|
|
||||
|
namespace Volo.Abp.BackgroundJobs.EntityFrameworkCore |
||||
|
{ |
||||
|
public class EfCoreBackgroundJobRepository : EfCoreRepository<IBackgroundJobsDbContext, BackgroundJobRecord, Guid>, IBackgroundJobRepository |
||||
|
{ |
||||
|
protected IClock Clock { get; } |
||||
|
|
||||
|
public EfCoreBackgroundJobRepository( |
||||
|
IDbContextProvider<IBackgroundJobsDbContext> dbContextProvider, |
||||
|
IClock clock) |
||||
|
: base(dbContextProvider) |
||||
|
{ |
||||
|
Clock = clock; |
||||
|
} |
||||
|
|
||||
|
public async Task<List<BackgroundJobRecord>> GetWaitingListAsync(int maxResultCount) |
||||
|
{ |
||||
|
return await DbSet |
||||
|
.Where(t => !t.IsAbandoned && t.NextTryTime <= Clock.Now) |
||||
|
.OrderByDescending(t => t.Priority) |
||||
|
.ThenBy(t => t.TryCount) |
||||
|
.ThenBy(t => t.NextTryTime) |
||||
|
.Take(maxResultCount) |
||||
|
.ToListAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,13 +1,12 @@ |
|||||
using Volo.Abp.Data; |
using Microsoft.EntityFrameworkCore; |
||||
|
using Volo.Abp.Data; |
||||
using Volo.Abp.EntityFrameworkCore; |
using Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
namespace Volo.Abp.BackgroundJobs.EntityFrameworkCore |
namespace Volo.Abp.BackgroundJobs.EntityFrameworkCore |
||||
{ |
{ |
||||
[ConnectionStringName("BackgroundJobs")] |
[ConnectionStringName("AbpBackgroundJobs")] |
||||
public interface IBackgroundJobsDbContext : IEfCoreDbContext |
public interface IBackgroundJobsDbContext : IEfCoreDbContext |
||||
{ |
{ |
||||
/* Add DbSet for each Aggregate Root here. Example: |
DbSet<BackgroundJobRecord> BackgroundJobs { get; } |
||||
* DbSet<Question> Questions { get; } |
|
||||
*/ |
|
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.BackgroundJobs.EntityFrameworkCore |
||||
|
{ |
||||
|
public class BackgroundJobRepositoryTests : BackgroundJobRepository_Tests<BackgroundJobsEntityFrameworkCoreTestModule> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -1,7 +0,0 @@ |
|||||
namespace Volo.Abp.BackgroundJobs.EntityFrameworkCore |
|
||||
{ |
|
||||
public class MyEntityRepository_Tests : MyEntityRepository_Tests<BackgroundJobsEntityFrameworkCoreTestModule> |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.BackgroundJobs.MongoDB |
||||
|
{ |
||||
|
public class BackgroundJobRepositoryTests : BackgroundJobRepository_Tests<BackgroundJobsMongoDbTestModule> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -1,7 +0,0 @@ |
|||||
namespace Volo.Abp.BackgroundJobs.MongoDB |
|
||||
{ |
|
||||
public class MyEntityRepository_Tests : MyEntityRepository_Tests<BackgroundJobsMongoDbTestModule> |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,35 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Timing; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.BackgroundJobs |
||||
|
{ |
||||
|
public abstract class BackgroundJobRepository_Tests<TStartupModule> : BackgroundJobsTestBase<TStartupModule> |
||||
|
where TStartupModule : IAbpModule |
||||
|
{ |
||||
|
private readonly IBackgroundJobRepository _backgroundJobRepository; |
||||
|
private readonly IClock _clock; |
||||
|
|
||||
|
protected BackgroundJobRepository_Tests() |
||||
|
{ |
||||
|
_backgroundJobRepository = GetRequiredService<IBackgroundJobRepository>(); |
||||
|
_clock = GetRequiredService<IClock>(); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData(2)] |
||||
|
[InlineData(5)] |
||||
|
public async Task GetWaitingListAsync(int maxResultCount) |
||||
|
{ |
||||
|
var backgroundJobs = await _backgroundJobRepository.GetWaitingListAsync(maxResultCount); |
||||
|
|
||||
|
backgroundJobs.Count.ShouldBeGreaterThan(0); |
||||
|
backgroundJobs.Count.ShouldBeLessThanOrEqualTo(maxResultCount); |
||||
|
|
||||
|
backgroundJobs.ForEach(j => j.IsAbandoned.ShouldBeFalse()); |
||||
|
backgroundJobs.ForEach(j => j.NextTryTime.ShouldBeLessThanOrEqualTo(_clock.Now.AddSeconds(1))); //1 second tolerance
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,8 +1,12 @@ |
|||||
using Volo.Abp.DependencyInjection; |
using System; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
namespace Volo.Abp.BackgroundJobs |
namespace Volo.Abp.BackgroundJobs |
||||
{ |
{ |
||||
public class BackgroundJobsTestData : ISingletonDependency |
public class BackgroundJobsTestData : ISingletonDependency |
||||
{ |
{ |
||||
|
public Guid JobId1 { get; } = Guid.NewGuid(); |
||||
|
public Guid JobId2 { get; } = Guid.NewGuid(); |
||||
|
public Guid JobId3 { get; } = Guid.NewGuid(); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,24 +1,71 @@ |
|||||
using Volo.Abp.DependencyInjection; |
using System; |
||||
using Volo.Abp.Guids; |
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Timing; |
||||
|
|
||||
namespace Volo.Abp.BackgroundJobs |
namespace Volo.Abp.BackgroundJobs |
||||
{ |
{ |
||||
public class BackgroundJobsTestDataBuilder : ITransientDependency |
public class BackgroundJobsTestDataBuilder : ITransientDependency |
||||
{ |
{ |
||||
private readonly IGuidGenerator _guidGenerator; |
private readonly BackgroundJobsTestData _testData; |
||||
private BackgroundJobsTestData _testData; |
private readonly IBackgroundJobRepository _backgroundJobRepository; |
||||
|
private readonly IClock _clock; |
||||
|
|
||||
public BackgroundJobsTestDataBuilder( |
public BackgroundJobsTestDataBuilder( |
||||
IGuidGenerator guidGenerator, |
BackgroundJobsTestData testData, |
||||
BackgroundJobsTestData testData) |
IBackgroundJobRepository backgroundJobRepository, |
||||
|
IClock clock) |
||||
{ |
{ |
||||
_guidGenerator = guidGenerator; |
|
||||
_testData = testData; |
_testData = testData; |
||||
|
_backgroundJobRepository = backgroundJobRepository; |
||||
|
_clock = clock; |
||||
} |
} |
||||
|
|
||||
public void Build() |
public void Build() |
||||
{ |
{ |
||||
|
_backgroundJobRepository.Insert( |
||||
|
new BackgroundJobRecord |
||||
|
{ |
||||
|
Id = _testData.JobId1, |
||||
|
JobName = "TestJobName", |
||||
|
JobArgs = "{ value: 1 }", |
||||
|
NextTryTime = _clock.Now.Subtract(TimeSpan.FromMinutes(1)), |
||||
|
Priority = BackgroundJobPriority.Normal, |
||||
|
IsAbandoned = false, |
||||
|
LastTryTime = null, |
||||
|
CreationTime = _clock.Now.Subtract(TimeSpan.FromMinutes(2)), |
||||
|
TryCount = 0 |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
_backgroundJobRepository.Insert( |
||||
|
new BackgroundJobRecord |
||||
|
{ |
||||
|
Id = _testData.JobId2, |
||||
|
JobName = "TestJobName", |
||||
|
JobArgs = "{ value: 2 }", |
||||
|
NextTryTime = _clock.Now.AddMinutes(42), |
||||
|
Priority = BackgroundJobPriority.AboveNormal, |
||||
|
IsAbandoned = true, |
||||
|
LastTryTime = _clock.Now.Subtract(TimeSpan.FromDays(1)), |
||||
|
CreationTime = _clock.Now.Subtract(TimeSpan.FromDays(2)), |
||||
|
TryCount = 3 |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
_backgroundJobRepository.Insert( |
||||
|
new BackgroundJobRecord |
||||
|
{ |
||||
|
Id = _testData.JobId3, |
||||
|
JobName = "TestJobName", |
||||
|
JobArgs = "{ value: 3 }", |
||||
|
NextTryTime = _clock.Now, |
||||
|
Priority = BackgroundJobPriority.BelowNormal, |
||||
|
IsAbandoned = false, |
||||
|
LastTryTime = _clock.Now.Subtract(TimeSpan.FromMinutes(60)), |
||||
|
CreationTime = _clock.Now.Subtract(TimeSpan.FromMinutes(90)), |
||||
|
TryCount = 2 |
||||
|
} |
||||
|
); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
@ -1,16 +0,0 @@ |
|||||
using System.Threading.Tasks; |
|
||||
using Volo.Abp.Modularity; |
|
||||
using Xunit; |
|
||||
|
|
||||
namespace Volo.Abp.BackgroundJobs |
|
||||
{ |
|
||||
public abstract class MyEntityRepository_Tests<TStartupModule> : BackgroundJobsTestBase<TStartupModule> |
|
||||
where TStartupModule : IAbpModule |
|
||||
{ |
|
||||
[Fact] |
|
||||
public async Task Test1() |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue