Abp vNext : 使用 BackgroundJobs
内存中的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
发布后台作业
在 Application 层,定义ApplicationService,
代码清单:AbpManual.Application/BackgroundJobs/BackgroundJobService.cs
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 会把这条记录删除,如下图所示:
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10亿数据,如何做迁移?
· 推荐几款开源且免费的 .NET MAUI 组件库
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 易语言 —— 开山篇
· Trae初体验