diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs
index 8cc44e0888..3862dd01da 100644
--- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs
+++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs
@@ -4,6 +4,7 @@ using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Auditing
{
+ //TODO: Rename to JsonAuditSerializer
public class JsonNetAuditSerializer : IAuditSerializer, ITransientDependency
{
protected AbpAuditingOptions Options;
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo.Abp.BackgroundJobs.csproj b/framework/src/Volo.Abp.BackgroundJobs/Volo.Abp.BackgroundJobs.csproj
index cc4ee2e787..90fb7bb890 100644
--- a/framework/src/Volo.Abp.BackgroundJobs/Volo.Abp.BackgroundJobs.csproj
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo.Abp.BackgroundJobs.csproj
@@ -14,7 +14,11 @@
+
+
+
+
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/AbpBackgroundJobsModule.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/AbpBackgroundJobsModule.cs
index a7bcf94526..6590b4788a 100644
--- a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/AbpBackgroundJobsModule.cs
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/AbpBackgroundJobsModule.cs
@@ -1,8 +1,18 @@
using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.BackgroundWorkers;
+using Volo.Abp.Guids;
+using Volo.Abp.Json;
using Volo.Abp.Modularity;
+using Volo.Abp.Timing;
namespace Volo.Abp.BackgroundJobs
{
+ [DependsOn(
+ typeof(AbpBackgroundWorkersModule),
+ typeof(AbpTimingModule),
+ typeof(AbpJsonModule),
+ typeof(AbpGuidsModule)
+ )]
public class AbpBackgroundJobsModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
@@ -10,4 +20,4 @@ namespace Volo.Abp.BackgroundJobs
context.Services.AddAssemblyOf();
}
}
-}
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJob.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJob.cs
new file mode 100644
index 0000000000..9ed0633806
--- /dev/null
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJob.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+
+namespace Volo.Abp.BackgroundJobs
+{
+ public abstract class BackgroundJob : IBackgroundJob
+ {
+ //TODO: Add UOW, Localization and other useful properties..?
+
+ public ILogger> Logger { get; set; }
+
+ protected BackgroundJob()
+ {
+ Logger = NullLogger>.Instance;
+ }
+
+ public abstract void Execute(TArgs args);
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobException.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobException.cs
new file mode 100644
index 0000000000..8e16d983bd
--- /dev/null
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobException.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Runtime.Serialization;
+using JetBrains.Annotations;
+
+namespace Volo.Abp.BackgroundJobs
+{
+ [Serializable]
+ public class BackgroundJobException : AbpException
+ {
+ [CanBeNull]
+ public BackgroundJobInfo BackgroundJob { get; set; }
+
+ [CanBeNull]
+ public object JobObject { get; set; }
+
+ ///
+ /// Creates a new object.
+ ///
+ public BackgroundJobException()
+ {
+
+ }
+
+ ///
+ /// Creates a new object.
+ ///
+ public BackgroundJobException(SerializationInfo serializationInfo, StreamingContext context)
+ : base(serializationInfo, context)
+ {
+
+ }
+
+ ///
+ /// Creates a new object.
+ ///
+ /// Exception message
+ /// Inner exception
+ public BackgroundJobException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobInfo.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobInfo.cs
new file mode 100644
index 0000000000..de9e4d83a6
--- /dev/null
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobInfo.cs
@@ -0,0 +1,126 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp.Timing;
+
+namespace Volo.Abp.BackgroundJobs
+{
+ ///
+ /// Represents a background job info that is used to persist jobs.
+ ///
+ public class BackgroundJobInfo
+ {
+ ///
+ /// Maximum length of .
+ /// Value: 512.
+ ///
+ public const int MaxJobTypeLength = 512;
+
+ ///
+ /// Maximum length of .
+ /// Value: 1 MB (1,048,576 bytes).
+ ///
+ public const int MaxJobArgsLength = 1024 * 1024;
+
+ ///
+ /// Default duration (as seconds) for the first wait on a failure.
+ /// Default value: 60 (1 minutes).
+ ///
+ public static int DefaultFirstWaitDuration { get; set; } //TODO: Move to configuration
+
+ ///
+ /// Default timeout value (as seconds) for a job before it's abandoned ().
+ /// Default value: 172,800 (2 days).
+ ///
+ public static int DefaultTimeout { get; set; } //TODO: Move to configuration
+
+ ///
+ /// Default wait factor for execution failures.
+ /// This amount is multiplated by last wait time to calculate next wait time.
+ /// Default value: 2.0.
+ ///
+ public static double DefaultWaitFactor { get; set; } //TODO: Move to configuration
+
+ public Guid Id { get; set; }
+
+ ///
+ /// Type of the job.
+ /// It's AssemblyQualifiedName of job type.
+ ///
+ [Required]
+ [StringLength(MaxJobTypeLength)]
+ public virtual string JobType { get; set; }
+
+ ///
+ /// Job arguments as JSON string.
+ ///
+ [Required]
+ [MaxLength(MaxJobArgsLength)]
+ public virtual string JobArgs { get; set; } //TODO: Consider to conver to byte[]
+
+ ///
+ /// Try count of this job.
+ /// A job is re-tried if it fails.
+ ///
+ public virtual short TryCount { get; set; }
+
+ ///
+ /// Creation time of this job.
+ ///
+ public virtual DateTime CreationTime { get; set; }
+
+ ///
+ /// Next try time of this job.
+ ///
+ public virtual DateTime NextTryTime { get; set; }
+
+ ///
+ /// Last try time of this job.
+ ///
+ public virtual DateTime? LastTryTime { get; set; }
+
+ ///
+ /// This is true if this job is continously failed and will not be executed again.
+ ///
+ public virtual bool IsAbandoned { get; set; }
+
+ ///
+ /// Priority of this job.
+ ///
+ public virtual BackgroundJobPriority Priority { get; set; }
+
+ static BackgroundJobInfo()
+ {
+ DefaultFirstWaitDuration = 60;
+ DefaultTimeout = 172800;
+ DefaultWaitFactor = 2.0;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public BackgroundJobInfo()
+ {
+ Priority = BackgroundJobPriority.Normal;
+ }
+
+ ///
+ /// Calculates next try time if a job fails.
+ /// Returns null if it will not wait anymore and job should be abandoned.
+ ///
+ ///
+ public virtual DateTime? CalculateNextTryTime(IClock clock) //TODO: Move to another place to override easier
+ {
+ var nextWaitDuration = DefaultFirstWaitDuration * (Math.Pow(DefaultWaitFactor, TryCount - 1));
+ var nextTryDate = LastTryTime.HasValue
+ ? LastTryTime.Value.AddSeconds(nextWaitDuration)
+ : clock.Now.AddSeconds(nextWaitDuration);
+
+ if (nextTryDate.Subtract(CreationTime).TotalSeconds > DefaultTimeout)
+ {
+ return null;
+ }
+
+ return nextTryDate;
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobManager.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobManager.cs
new file mode 100644
index 0000000000..bd9f729a5d
--- /dev/null
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobManager.cs
@@ -0,0 +1,182 @@
+using System;
+using System.Diagnostics;
+using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Volo.Abp.BackgroundWorkers;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Guids;
+using Volo.Abp.Threading;
+using Volo.Abp.Timing;
+
+namespace Volo.Abp.BackgroundJobs
+{
+ ///
+ /// Default implementation of .
+ ///
+ public class BackgroundJobManager : PeriodicBackgroundWorkerBase, IBackgroundJobManager, ISingletonDependency
+ {
+ ///
+ /// Interval between polling jobs from .
+ /// Default value: 5000 (5 seconds).
+ ///
+ public static int JobPollPeriod { get; set; } //TODO: Move to options
+
+ protected IServiceProvider ServiceProvider { get; }
+ protected IClock Clock { get; }
+ protected IBackgroundJobSerializer Serializer { get; }
+ protected IGuidGenerator GuidGenerator { get; }
+ protected IBackgroundJobStore Store { get; }
+
+ static BackgroundJobManager()
+ {
+ JobPollPeriod = 5000;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public BackgroundJobManager(
+ IServiceProvider serviceProvider,
+ IClock clock,
+ IBackgroundJobSerializer serializer,
+ IBackgroundJobStore store,
+ IGuidGenerator guidGenerator,
+ AbpTimer timer)
+ : base(timer)
+ {
+ ServiceProvider = serviceProvider;
+ Clock = clock;
+ Serializer = serializer;
+ GuidGenerator = guidGenerator;
+ Store = store;
+
+ Timer.Period = JobPollPeriod;
+ }
+
+ public async Task EnqueueAsync(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, TimeSpan? delay = null)
+ where TJob : IBackgroundJob
+ {
+ var jobInfo = new BackgroundJobInfo
+ {
+ Id = GuidGenerator.Create(),
+ JobType = typeof(TJob).AssemblyQualifiedName,
+ JobArgs = Serializer.Serialize(args),
+ Priority = priority,
+ CreationTime = Clock.Now,
+ NextTryTime = Clock.Now
+ };
+
+ if (delay.HasValue)
+ {
+ jobInfo.NextTryTime = Clock.Now.Add(delay.Value);
+ }
+
+ await Store.InsertAsync(jobInfo);
+
+ return jobInfo.Id;
+ }
+
+ public async Task DeleteAsync(Guid jobId)
+ {
+ var jobInfo = await Store.GetAsync(jobId);
+ if (jobInfo == null)
+ {
+ return false;
+ }
+
+ await Store.DeleteAsync(jobInfo);
+ return true;
+ }
+
+ protected override void DoWork()
+ {
+ var waitingJobs = AsyncHelper.RunSync(() => Store.GetWaitingJobsAsync(1000));
+
+ foreach (var job in waitingJobs)
+ {
+ TryProcessJob(job);
+ }
+ }
+
+ private void TryProcessJob(BackgroundJobInfo jobInfo)
+ {
+ try
+ {
+ jobInfo.TryCount++;
+ jobInfo.LastTryTime = Clock.Now;
+
+ var jobType = Type.GetType(jobInfo.JobType);
+ using (var scope = ServiceProvider.CreateScope())
+ {
+ var job = scope.ServiceProvider.GetService(jobType);
+ if (job == null)
+ {
+ throw new AbpException("JobType 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);
+ }
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobManagerExtensions.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobManagerExtensions.cs
new file mode 100644
index 0000000000..b6cbca221b
--- /dev/null
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobManagerExtensions.cs
@@ -0,0 +1,26 @@
+using System;
+using Volo.Abp.Threading;
+
+namespace Volo.Abp.BackgroundJobs
+{
+ ///
+ /// Some extension methods for .
+ ///
+ public static class BackgroundJobManagerExtensions
+ {
+ ///
+ /// Enqueues a job to be executed.
+ ///
+ /// Type of the job.
+ /// Type of the arguments of job.
+ /// Background job manager reference
+ /// Job arguments.
+ /// Job priority.
+ /// Job delay (wait duration before first try).
+ public static void Enqueue(this IBackgroundJobManager backgroundJobManager, TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, TimeSpan? delay = null)
+ where TJob : IBackgroundJob
+ {
+ AsyncHelper.RunSync(() => backgroundJobManager.EnqueueAsync(args, priority, delay));
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobOptions.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobOptions.cs
new file mode 100644
index 0000000000..abd89e6e40
--- /dev/null
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobOptions.cs
@@ -0,0 +1,12 @@
+namespace Volo.Abp.BackgroundJobs
+{
+ public class BackgroundJobOptions
+ {
+ public bool IsJobExecutionEnabled { get; set; }
+
+ public BackgroundJobOptions()
+ {
+ IsJobExecutionEnabled = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobPriority.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobPriority.cs
new file mode 100644
index 0000000000..7c5f28dbeb
--- /dev/null
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobPriority.cs
@@ -0,0 +1,33 @@
+namespace Volo.Abp.BackgroundJobs
+{
+ ///
+ /// Priority of a background job.
+ ///
+ public enum BackgroundJobPriority : byte
+ {
+ ///
+ /// Low.
+ ///
+ Low = 5,
+
+ ///
+ /// Below normal.
+ ///
+ BelowNormal = 10,
+
+ ///
+ /// Normal (default).
+ ///
+ Normal = 15,
+
+ ///
+ /// Above normal.
+ ///
+ AboveNormal = 20,
+
+ ///
+ /// High.
+ ///
+ High = 25
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJob.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJob.cs
new file mode 100644
index 0000000000..e7c942ec4c
--- /dev/null
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJob.cs
@@ -0,0 +1,14 @@
+namespace Volo.Abp.BackgroundJobs
+{
+ ///
+ /// Defines interface of a background job.
+ ///
+ public interface IBackgroundJob
+ {
+ ///
+ /// Executes the job with the .
+ ///
+ /// Job arguments.
+ void Execute(TArgs args);
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJobManager.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJobManager.cs
new file mode 100644
index 0000000000..526e6c84d6
--- /dev/null
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJobManager.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Threading.Tasks;
+using Volo.Abp.BackgroundWorkers;
+
+namespace Volo.Abp.BackgroundJobs
+{
+ //TODO: Create a non-generic EnqueueAsync extension method to IBackgroundJobManager which takes types as input parameters rather than generic parameters.
+ ///
+ /// Defines interface of a job manager.
+ ///
+ public interface IBackgroundJobManager : IBackgroundWorker
+ {
+ ///
+ /// Enqueues a job to be executed.
+ ///
+ /// Type of the job.
+ /// Type of the arguments of job.
+ /// Job arguments.
+ /// Job priority.
+ /// Job delay (wait duration before first try).
+ /// Unique identifier of a background job.
+ Task EnqueueAsync(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, TimeSpan? delay = null)
+ where TJob : IBackgroundJob;
+
+ ///
+ /// Deletes a job with the specified jobId.
+ ///
+ /// The Job Unique Identifier.
+ /// True on a successfull state transition, false otherwise.
+ Task DeleteAsync(Guid jobId);
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJobSerializer.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJobSerializer.cs
new file mode 100644
index 0000000000..b0e80001ad
--- /dev/null
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJobSerializer.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Volo.Abp.BackgroundJobs
+{
+ public interface IBackgroundJobSerializer
+ {
+ string Serialize(object obj);
+
+ object Deserialize(string value, Type type);
+ }
+}
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJobStore.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJobStore.cs
new file mode 100644
index 0000000000..1c18d2a273
--- /dev/null
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJobStore.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Volo.Abp.BackgroundJobs
+{
+ ///
+ /// Defines interface to store/get background jobs.
+ ///
+ public interface IBackgroundJobStore
+ {
+ ///
+ /// Gets a BackgroundJobInfo based on the given jobId.
+ ///
+ /// The Job Unique Identifier.
+ /// The BackgroundJobInfo object.
+ Task GetAsync(Guid jobId);
+
+ ///
+ /// Inserts a background job.
+ ///
+ /// Job information.
+ Task InsertAsync(BackgroundJobInfo jobInfo);
+
+ ///
+ /// Gets waiting jobs. It should get jobs based on these:
+ /// Conditions: !IsAbandoned And NextTryTime <= Clock.Now.
+ /// Order by: Priority DESC, TryCount ASC, NextTryTime ASC.
+ /// Maximum result: .
+ ///
+ /// Maximum result count.
+ Task> GetWaitingJobsAsync(int maxResultCount);
+
+ ///
+ /// Deletes a job.
+ ///
+ /// Job information.
+ Task DeleteAsync(BackgroundJobInfo jobInfo);
+
+ ///
+ /// Updates a job.
+ ///
+ /// Job information.
+ Task UpdateAsync(BackgroundJobInfo jobInfo);
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/JsonBackgroundJobSerializer.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/JsonBackgroundJobSerializer.cs
new file mode 100644
index 0000000000..361058e5c8
--- /dev/null
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/JsonBackgroundJobSerializer.cs
@@ -0,0 +1,30 @@
+using System;
+using Volo.Abp.Json;
+
+namespace Volo.Abp.BackgroundJobs
+{
+ public class JsonBackgroundJobSerializer : IBackgroundJobSerializer
+ {
+ private readonly IJsonSerializer _jsonSerializer;
+
+ public JsonBackgroundJobSerializer(IJsonSerializer jsonSerializer)
+ {
+ _jsonSerializer = jsonSerializer;
+ }
+
+ public string Serialize(object obj)
+ {
+ return _jsonSerializer.Serialize(obj);
+ }
+
+ public object Deserialize(string value, Type type)
+ {
+ return _jsonSerializer.Deserialize(type, value);
+ }
+
+ public T Deserialize(string value)
+ {
+ return _jsonSerializer.Deserialize(value);
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/NullBackgroundJobStore.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/NullBackgroundJobStore.cs
new file mode 100644
index 0000000000..42a6656567
--- /dev/null
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/NullBackgroundJobStore.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Volo.Abp.BackgroundJobs
+{
+ ///
+ /// Null pattern implementation of .
+ /// It's used if is not implemented by actual persistent store
+ /// and job execution is not enabled () for the application.
+ ///
+ public class NullBackgroundJobStore : IBackgroundJobStore
+ {
+ public Task GetAsync(Guid jobId)
+ {
+ return Task.FromResult((BackgroundJobInfo)null);
+ }
+
+ public Task InsertAsync(BackgroundJobInfo jobInfo)
+ {
+ return Task.CompletedTask;
+ }
+
+ public Task> GetWaitingJobsAsync(int maxResultCount)
+ {
+ return Task.FromResult(new List());
+ }
+
+ public Task DeleteAsync(BackgroundJobInfo jobInfo)
+ {
+ return Task.CompletedTask;
+ }
+
+ public Task UpdateAsync(BackgroundJobInfo jobInfo)
+ {
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file