內存中的BackgroundJobs
第1步:在項目中應用如下包:
<PackageReference Include="Volo.Abp.BackgroundJobs" Version="6.0.1" />
然後添加模塊依賴
using AbpManual;
using Volo.Abp.Application;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.Emailing;
using Volo.Abp.MailKit;
using Volo.Abp.Modularity;
namespace AbpManaul
{
[DependsOn(
typeof(AbpBackgroundJobsModule),
...
)]
public class AbpManualApplicationModule : AbpModule
{
}
}
第2步:定義類 EmailSendingArgs
,用於保存後臺作業的數據
namespace AbpManual.BackgroundJobs
{
/// <summary>BackgroundJob 的會自動進行重試
/// 後臺作業數據
/// </summary>
public class EmailSendingArgs
{
public string EmailAddress { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
}
}
第3步:定義後臺作業類 EmailSendingJob
同步版本,繼承BackgroundJob<T>
using Microsoft.Extensions.Logging;
using Volo.Abp;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Emailing;
namespace AbpManual.BackgroundJobs
{
/// <summary>
/// https://docs.abp.io/zh-Hans/abp/latest/Background-Jobs
/// 後臺作業是一個實現IBackgroundJob<TArgs>接口或繼承自BackgroundJob<TArgs>類的類
/// </summary>
public class EmailSendingJob : BackgroundJob<EmailSendingArgs>, ITransientDependency
{
private readonly ILogger<EmailSendingJob> _logger;
public EmailSendingJob(
ILogger<EmailSendingJob> logger)
{
_logger = logger;
}
public override void Execute(EmailSendingArgs args)
{
// 模擬隨機產生異常,看看後臺作業是否因失敗再次執行
if (RandomHelper.GetRandom(0, 10) < 5)
{
throw new ApplicationException("A sample exception from the EmailSendingJob!");
}
_logger.LogInformation($"############### EmailSendingJob: 郵件已成功發送至郵箱:{args.EmailAddress} ###############");
}
}
}
異步版本,繼承AsyncBackgroundJob<T>
, 如下代碼所示:
using Microsoft.Extensions.Logging;
using Volo.Abp;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Emailing;
namespace AbpManual.BackgroundJobs
{
/// <summary>
/// https://docs.abp.io/zh-Hans/abp/latest/Background-Jobs
/// 後臺作業是一個實現IBackgroundJob<TArgs>接口或繼承自BackgroundJob<TArgs>類的類
/// </summary>
public class EmailSendingJob : AsyncBackgroundJob<EmailSendingArgs>, ITransientDependency
{
private readonly IEmailSender _emailSender;
private readonly ILogger<EmailSendingJob> _logger;
public EmailSendingJob(
IEmailSender emailSender,
ILogger<EmailSendingJob> logger)
{
_emailSender = emailSender;
_logger = logger;
}
public override async Task ExecuteAsync(EmailSendingArgs args)
{
// 模擬隨機產生異常,看看後臺作業是否因失敗再次執行
if (RandomHelper.GetRandom(0, 10) < 5)
{
throw new ApplicationException("A sample exception from the EmailSendingJob!");
}
_logger.LogInformation($"############### EmailSendingJob: 郵件已成功發送至郵箱:{args.EmailAddress} ###############");
// 發送郵件
await _emailSender.SendAsync(
args.EmailAddress,
args.Subject,
args.Body
);
}
}
}
第4步:使用 IBackgroundJobManager
發佈後臺作業
using AbpManual.BackgroundJobs;
using Volo.Abp.Application.Services;
using Volo.Abp.BackgroundJobs;
namespace AbpManaul.BackgroundJobs
{
public class BackgroundJobService : ApplicationService, IBackgroundJobService
{
/// <summary>
/// 默認後臺作業管理器
/// https://docs.abp.io/zh-Hans/abp/latest/Background-Jobs
/// ABP framework 包含一個簡單的 IBackgroundJobManager 實現;
/// </summary>
private readonly IBackgroundJobManager _backgroundJobManager;
public BackgroundJobService(IBackgroundJobManager backgroundJobManager)
{
_backgroundJobManager = backgroundJobManager;
}
public async Task RegisterAsync(RegisterInput input)
{
//TODO: 創建一個新用戶到數據庫中...
await _backgroundJobManager.EnqueueAsync(
new EmailSendingArgs
{
EmailAddress = input.EmailAddress,
Subject = "You've successfully registered!",
Body = "恭喜你註冊成功!"
}
);
}
}
}
至此,就完成了後臺作業的全部過程,並且,如果此次作業執行失敗,執行失敗的作業會被保存在內存中,過一段時間後(默認是60秒 x 等待時間因子(默認值爲2)),BackgroundJob 的會自動進行重試。
BackgroundJobs Moudle
上一節,BackgroundJobs 的執行失敗的作業是存儲內存中, 雖然也可以實現 BackgroundJob 的重試,但是畢竟是保存在內存中,如果重啓了進程,內存中的任務就會丟失,
而 Abp vNext 社區版的 BackgroundJobs Moudle, 參見:後臺作業模塊,已經實現了將 BackgroundJob 存儲到數據庫中.
只需要在現有的項目引入即可。下面是在現有項目中引入BackgroundJobs Moudle 的的步驟:
第零步:照搬與內存中的BackgroundJobs 中的的幾個步驟
第一步:AbpManual.Domain.Shared
在該項目引入如下模塊:
<ItemGroup>
<PackageReference Include="Volo.Abp.BackgroundJobs.Domain.Shared" Version="6.0.1" />
</ItemGroup>
添加模塊依賴:
[DependsOn(
typeof(AbpBackgroundJobsDomainSharedModule)
)]
public class AbpManualDomainSharedModule : AbpModule
{
}
第二步:AbpManual.Domain
在該項目引入如下模塊:
<ItemGroup>
<PackageReference Include="Volo.Abp.BackgroundJobs.Domain" Version="6.0.1" />
</ItemGroup>
添加模塊依賴:
using Volo.Abp.BackgroundJobs;
using Volo.Abp.Modularity;
namespace AbpManual;
[DependsOn(
typeof(AbpManualDomainSharedModule),
typeof(AbpBackgroundJobsDomainModule)
)]
public class AbpManualDomainModule : AbpModule
{
}
第三步:AbpManual.EntityFrameworkCore
在該項目引入如下模塊:
<ItemGroup>
<PackageReference Include="Volo.Abp.BackgroundJobs.EntityFrameworkCore" Version="6.0.1" />
</ItemGroup>
添加模塊依賴:
namespace AbpManual.EntityFrameworkCore;
[DependsOn(
...
typeof(AbpBackgroundJobsEntityFrameworkCoreModule)
)]
public class AbpManualEntityFrameworkCoreModule : AbpModule
{
...
}
第四步:添加 BackgroundJobsModule 模塊的數據庫遷移
首先,在 AbpManualDbContext
類中添加 BackgroundJobsModule 模塊的數據庫配置
namespace AbpManual.EntityFrameworkCore;
public class AbpManualDbContext :
AbpDbContext<AbpManualDbContext>
{
public AbpManualDbContext(DbContextOptions<AbpManualDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
...
builder.ConfigureBackgroundJobs();
...
}
}
然後添加數據庫遷移
add-migration InitialBackgroundJobsMoudle
將遷移更新到數據庫
update-database
或者 運行項目 AbpManual.DbMigrator 進行數據庫更新,
更新成功後,會新增一張數據庫表 AbpBackgroundJobs,如下圖所示:
第五步:在項目 AbpManual.Web 或 AbpManual.HttpApi.Host 中 ,配置 BackgroundJob 的參數
配置 BackgroundJob 的參數,以便更快重試失敗的後臺作業,立馬能查看的測試結果
public class AbpManualWebModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
ConfigureBackgroundJob(context, configuration);
...
}
/// <summary>
/// 配置後臺作業
/// </summary>
/// <param name="context"></param>
/// <param name="configuration"></param>
private void ConfigureBackgroundJob(ServiceConfigurationContext context, IConfiguration configuration)
{
Configure<AbpBackgroundJobWorkerOptions>(options =>
{
options.DefaultTimeout = 864000; //10 days (as seconds)
//配置重試參數,以便能快速測試效果
options.JobPollPeriod = 1000; // 優先級
options.DefaultFirstWaitDuration = 10; // 重試間隔,單位秒
options.DefaultWaitFactor = 1; // 等待時間因子
});
// 默認後臺管理器不支持多進程執行相同的作業隊列.
// 所以, 如果你的應用程序中有多個正在運行的實現,並且使用的是默認的後臺管理器, 你應該只在一個應用程序實例進程中啓用作業隊列.
//Configure<AbpBackgroundJobOptions>(options =>
// {
// options.IsJobExecutionEnabled = false; //禁用作業執行
// });
}
第六步:測試
點擊執行按鈕,如果執行作業失敗,如下圖所示:
這時,數據庫表AbpBackgroundJobs 中會插入這個執行失敗作業的記錄,如下圖所示:
在配置指定的時間後,失敗的作業會再次被執行,如果還是失敗,數據庫表 AbpBackgroundJobs的 TryCount
會累加1,並更新相關其它字段,如下圖所示:
如果最終這條後臺作業執行成功,如下圖所示:
數據庫表AbpBackgroundJobs 會把這條記錄刪除,如下圖所示: