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; |
|||
|
|||
namespace Volo.Abp.BackgroundJobs.EntityFrameworkCore |
|||
{ |
|||
[ConnectionStringName("BackgroundJobs")] |
|||
[ConnectionStringName("AbpBackgroundJobs")] |
|||
public interface IBackgroundJobsDbContext : IEfCoreDbContext |
|||
{ |
|||
/* Add DbSet for each Aggregate Root here. Example: |
|||
* DbSet<Question> Questions { get; } |
|||
*/ |
|||
DbSet<BackgroundJobRecord> BackgroundJobs { 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 |
|||
{ |
|||
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 Volo.Abp.Guids; |
|||
using System; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Timing; |
|||
|
|||
namespace Volo.Abp.BackgroundJobs |
|||
{ |
|||
public class BackgroundJobsTestDataBuilder : ITransientDependency |
|||
{ |
|||
private readonly IGuidGenerator _guidGenerator; |
|||
private BackgroundJobsTestData _testData; |
|||
private readonly BackgroundJobsTestData _testData; |
|||
private readonly IBackgroundJobRepository _backgroundJobRepository; |
|||
private readonly IClock _clock; |
|||
|
|||
public BackgroundJobsTestDataBuilder( |
|||
IGuidGenerator guidGenerator, |
|||
BackgroundJobsTestData testData) |
|||
BackgroundJobsTestData testData, |
|||
IBackgroundJobRepository backgroundJobRepository, |
|||
IClock clock) |
|||
{ |
|||
_guidGenerator = guidGenerator; |
|||
_testData = testData; |
|||
_backgroundJobRepository = backgroundJobRepository; |
|||
_clock = clock; |
|||
} |
|||
|
|||
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