ABP:BackgroundJob/Quartz 结合业务实现定时发送

news2024/11/27 14:37:18

需求描述:我在使用ABP框架,现在想实现一个定时任务功能,描述:每天八点调用特定接口,调用n次后结束不再调用。相关的数据都来自于一个特定的实体“fuck”。

解决方案:可以使用ABP框架自带的定时任务功能来实现

解决步骤

  • 创建一个名为 "FuckJob" 的后台任务类,继承 BackgroundJob 类。
  • 在 ExecuteAsync 方法中编写调用特定接口的逻辑,并在每次调用后将 "fuck" 实体中的相关数据进行更新。
  • 在启动类 YourProjectNameWebHostModule 中,使用 Configure<AbpBackgroundJobOptions> 方法来配置任务的执行时间。例如:

详细代码:

1. 创建一个名为 "FuckJob" 的后台任务类,继承 BackgroundJob 类,并实现 ExecuteAsync 方法:

public class FuckJob : BackgroundJob
{
    private readonly IRepository<Fuck, Guid> _fuckRepository;

    public FuckJob(IRepository<Fuck, Guid> fuckRepository)
    {
        _fuckRepository = fuckRepository;
    }

    public override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // 获取 "fuck" 实体
        var fuck = await _fuckRepository.FirstOrDefaultAsync();

        // 调用特定接口的逻辑
        // ...

        // 更新 "fuck" 实体的相关数据
        fuck.SomeProperty = someValue;
        await _fuckRepository.UpdateAsync(fuck);
    }
}

2. 在启动类 YourProjectNameWebHostModule 中,注册 "FuckJob" 类,并配置任务的执行时间

[DependsOn(
    typeof(AbpBackgroundJobsModule),
    typeof(YourProjectNameEntityFrameworkCoreModule)
)]
public class YourProjectNameWebHostModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        // 注册 "FuckJob" 类
        context.Services.AddTransient<FuckJob>();

        Configure<AbpBackgroundJobOptions>(options =>
        {
            options.AddJob<FuckJob>(job => job
                .WithInterval(TimeSpan.FromDays(1)) // 每天执行一次
                .WithDescription("每天八点调用特定接口,调用n次后结束不再调用")
                .WithTolerateTime(TimeSpan.FromMinutes(30)) // 允许任务延迟30分钟
                .WithRunTimes(10) // 执行10次后结束
                .Build());
        });
    }
}

优化代码,相关数据取自仓储的实体

public class YourProjectNameWebHostModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        context.Services.AddTransient<FuckJob>(provider =>
        {
            var fuckRepository = provider.GetService<IRepository<Fuck, Guid>>();

            // 获取 "fuck" 实体中的数据
            var fuck = fuckRepository.FirstOrDefault();
            var executeTimes = fuck.ExecuteTimes;
            var maxRunTimes = fuck.MaxRunTimes;

            return new FuckJob(fuckRepository, executeTimes, maxRunTimes);
        });

        Configure<AbpBackgroundJobOptions>(options =>
        {
            options.AddJob<FuckJob>(job => job
                .WithInterval(TimeSpan.FromDays(1)) // 每天执行一次
                .WithDescription("每天八点调用特定接口,调用n次后结束不再调用")
                .WithTolerateTime(TimeSpan.FromMinutes(30)) // 允许任务延迟30分钟
                .WithRunTimes(maxRunTimes) // 执行 n 次后结束
                .Build());
        });
    }
}

结合业务拓展

实际业务需求中,有一个开关来添加和删除后台任务。

翻译为技术需求:在启动类之外的地方AddJob<FuckJob>?因为我的想法是前端调用某个接口然后启动后台定时任务。同时,还存在一个接口也可以删除这个定时任务。

1. 在前端调用某个接口时,通过 IBackgroundJobManager 接口的 AddJobAsync 方法来添加后台任务,例如:

返回值为添加的job的Guid

应该有另外一张表来存储这些后台任务

public class YourController : YourProjectNameControllerBase
{
    private readonly IBackgroundJobManager _backgroundJobManager;

    public YourController(IBackgroundJobManager backgroundJobManager)
    {
        _backgroundJobManager = backgroundJobManager;
    }

    public async Task<IActionResult> AddFuckJob()
    {
        // 获取 "fuck" 实体中的数据
        var fuck = await _fuckRepository.FirstOrDefaultAsync();
        var executeTimes = fuck.ExecuteTimes;
        var maxRunTimes = fuck.MaxRunTimes;

        // 添加后台任务
        await _backgroundJobManager.AddJobAsync(
            new JobInvocation(
                typeof(FuckJob),
                new JobArgs
                {
                    Args = new object[] { executeTimes, maxRunTimes }
                }
            )
        );

        // 返回任务标识符
        return Ok(jobId);
    }
}

2. 在另一个接口中,通过 IBackgroundJobManager 接口的 RemoveAsync 方法来删除后台任务,例如:

public class YourController : YourProjectNameControllerBase
{
    private readonly IBackgroundJobManager _backgroundJobManager;

    public YourController(IBackgroundJobManager backgroundJobManager)
    {
        _backgroundJobManager = backgroundJobManager;
    }

    public async Task<IActionResult> RemoveFuckJob()
    {
        // 删除后台任务
        await _backgroundJobManager.RemoveAsync(typeof(FuckJob));

        return Ok();
    }
}

整体实现思路

在application层 推送一个eto出去,ILocalEventHandler内去触发一个定时任务,那么这个定时任务的逻辑被定义在domian层(manager结尾的文件)。

domain层处理backgroundJob,多个接口相关后台任务的增加删除。

那么数据源独自一张单独的表,每次触发开关时候要做两件事

1. 修改数据源实体

2. 删除/增加 typeof(xxxx)的backgroundJob

和 quartz的区别?

我的实现方式是使用 ABP 框架提供的后台任务管理功能,而 Quartz 是一个独立的任务调度框架。它们的区别主要有以下几点:

  1. ABP 框架的后台任务管理功能是直接集成在框架中的,使用起来比较方便,而 Quartz 则需要单独引入和配置。

  2. ABP 框架的后台任务管理功能支持分布式环境下的任务调度,可以通过分布式锁来避免任务重复执行,而 Quartz 则需要额外配置分布式环境下的任务调度。

  3. ABP 框架的后台任务管理功能支持多种存储方式,可以使用数据库、Redis 等作为后台任务的存储介质,而 Quartz 则默认使用数据库作为存储介质。

  4. ABP 框架的后台任务管理功能提供了一些常用的任务调度方式,例如简单定时、循环定时、延迟执行等,使用起来比较方便,而 Quartz 则需要手动编写 Cron 表达式等。

综上所述,ABP 框架的后台任务管理功能适用于一些简单的任务调度场景,而 Quartz 则适用于更加复杂和灵活的任务调度场景。但是,在使用 Quartz 时需要额外进行配置和学习成本比较高,而 ABP 框架的后台任务管理功能则是直接集成在框架中,使用起来比较方便。

用quartz来实现一遍这个需求

要定义一个Job类,你需要继承Quartz的Job类,并实现execute方法。在这个方法中,你可以编写需要执行的逻辑。

在你的情况下,你想传入一些参数来执行定时任务,你可以使用JobDataMap来传递参数。JobDataMap是JobExecutionContext的一部分,可以在执行任务时获取。

以下是一个示例代码,展示了如何定义一个Job类,并传递参数:

public class MyJob : IJob
{
    public void Execute(IJobExecutionContext context)
    {
        // 从JobDataMap中获取参数
        JobDataMap dataMap = context.JobDetail.JobDataMap;
        int x = dataMap.GetInt("x");
        int n = dataMap.GetInt("n");
        
        // 执行你的逻辑
        // 调用指定接口,执行n天后结束
    }
}

接下来,你需要实现一个接口,这个接口的功能是添加一个定时任务,并传入相关参数。你可以创建一个定时任务管理类,其中包含添加任务的方法。

以下是一个示例代码,展示了如何添加定时任务并传递参数:

public class SchedulerManager
{
    private readonly IScheduler _scheduler;

    public SchedulerManager(IScheduler scheduler)
    {
        _scheduler = scheduler;
    }

    public async Task AddJob(FuckEntity fuckEntity)
    {
        // 创建一个JobDetail实例,传入参数
        JobDataMap dataMap = new JobDataMap();
        dataMap.Put("x", fuckEntity.X);
        dataMap.Put("n", fuckEntity.N);
        
        IJobDetail job = JobBuilder.Create<MyJob>()
            .WithIdentity("myJob")
            .UsingJobData(dataMap)
            .Build();

        // 创建一个Trigger实例,设置定时调度规则
        ITrigger trigger = TriggerBuilder.Create()
            .WithIdentity("myTrigger")
            .WithDailyTimeIntervalSchedule(x => x.StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(fuckEntity.X, 0)))
            .EndAt(DateTimeOffset.Now.AddDays(fuckEntity.N))
            .Build();

        // 将Job和Trigger添加到调度器中
        await _scheduler.ScheduleJob(job, trigger);
    }
}

 

在上述代码中,IScheduler是Quartz框架提供的接口,用于管理和调度Job和Trigger。你可以通过依赖注入将其注入到 SchedulerManager 类中。

请注意,上述代码中的FuckEntity是一个占位符,你需要替换为你自己的实体类。

最后,你可以通过调用SchedulerManagerAddJob方法来添加一个定时任务,并传入相关参数:

FuckEntity fuckEntity = new FuckEntity { X = 12, N = 7 };
await schedulerManager.AddJob(fuckEntity);

 这样,你就可以实现一个定时任务,并传递相关参数。每天指定的时间点,定时任务将会执行调用指定的接口,执行n天后结束。

TriggerBuilder.Create().WithIdentity("myTrigger")的WithIdentity是什么?

在ABP(ASP.NET Boilerplate)框架中,TriggerBuilder.Create().WithIdentity("myTrigger")中的WithIdentity方法用于为触发器分配一个唯一的标识符,这个标识符通常被用于后续操作。

WithIdentity方法接受一个字符串参数作为触发器的标识符。这个参数可以是任何你指定的字符串,用于唯一标识触发器。在后续操作中,你可以使用这个标识符来引用和管理这个触发器。

一个常见的用例是在调度器中创建多个触发器时,使用不同的标识符来区分它们。这样,你可以根据标识符来管理和操作各个触发器,例如启动、停止或删除它们。标识符还可以用于记录日志或其他跟踪目的。

示例代码如下:

TriggerBuilder.Create()
    .WithIdentity("myTrigger") // 设置触发器标识符为 "myTrigger"
    // 其他设置...
    .Build();

Conversation History

https://monica.im/s/2e53179e?locale=enhttps://monica.im/s/2e53179e?locale=en

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/844197.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅聊Cesium.js 后处理原理

浅聊Cesium.js 后处理原理 使用例子: const stages viewer.scene.postProcessStages;const silhouette Cesium.PostProcessStageLibrary.createSilhouetteStage() silhouette.enabled true; stages.add(silhouette);silhouette.uniforms.color Cesium.Color.LIME;涉及到相…

linux内网穿透应用场景有哪些?快解析有什么用处?

随着网络技术的不断发展&#xff0c;无论是工作上还是在生活中人们对网络的依赖和需求越来越高。Linux内网穿透作为一种创新的解决方案&#xff0c;为我们提供了无限可能。 首先我们了解一下Linux操作系统。Linux是一套免费使用和自由传播的类Unix操作系统&#xff0c;是一个基…

流量卡线上销户全教程,剩余的话费还有可能给你退回来!

线上就可以注销手机卡你知道吗&#xff1f;目前三大运营商都开通了线上销户业务了&#xff0c;而且用不完的话费还可以退回来&#xff0c;建议大家点赞收藏起来&#xff0c;以免有需要的时候找不到了&#xff0c;大家好&#xff0c;我是流量卡葫芦妹。 ​ OK&#xff0c;不多废…

进程、线程、协程

目录 进程、线程、协程的概念 进程、线程、协程的上下文切换 使用协程的注意事项 协程与线程、进程的区别 进程、线程、协程的概念 进程&#xff1a; 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程…

redis原理 1:鞭辟入里 —— 线程 IO 模型

Redis 是个单线程程序&#xff01;这点必须铭记。 也许你会怀疑高并发的 Redis 中间件怎么可能是单线程。很抱歉&#xff0c;它就是单线程&#xff0c;你的怀疑暴露了你基础知识的不足。莫要瞧不起单线程&#xff0c;除了 Redis 之外&#xff0c;Node.js 也是单线程&#xff0c…

封装上传文件组件(axios,onUploadProgress,取消请求)

目录 定时模拟进度条 方法 A.axios B.xhr 取消请求​​​​​​​ 完整代码 A.自定义上传组件 B.二次封装组件 情况 增加cancelToken不生效&#xff0c;刷新页面 进度条太快->设置浏览器网速 定时模拟进度条 startUpload() {if (!this.file) return;const totalS…

AWS 中文入门开发教学 49- S3 - 区域间复制

知识点 S3 存储桶内容在全球区域间进行复制官网 https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/replication.html 实战演习 在东京区建立存储桶 Name: woyaofuzhi启用版本控制(完成区域间复制必须开启版本控制) 在新加坡区建立存储桶 Name: woyaofuzhibac…

科技感响应式管理系统后台登录页ui设计html模板

做了一个科技感的后台管理系统登录页设计&#xff0c;并且尝试用响应式布局把前端html写了出来&#xff0c;发现并没有现象中的那么容易&#xff0c;chrome等标准浏览器都显示的挺好&#xff0c;但IE11下面却出现了很多错位&#xff0c;兼容起来还是挺费劲的&#xff0c;真心不…

【Python从入门到进阶】31、使用JSONPath解析淘票票网站地区接口数据

接上篇《30、JSONPath的介绍和使用》 上一篇我们介绍了JSONPath的基础和具体使用&#xff0c;本篇我们来具体使用JSONPath&#xff0c;来解析淘票票网站的地区接口数据。 一、引言 1、JsonPath的作用和用途&#xff1f; JsonPath是一种用于在JSON数据中进行查询和提取的表达…

Python测试框架pytest:测试用例、查找子集、参数化、跳过

Pytest是一个基于python的测试框架&#xff0c;用于编写和执行测试代码。pytest主要用于API测试&#xff0c;可以编写代码来测试API、数据库、UI等。 pytest是一个非常成熟的全功能的Python测试框架&#xff0c;主要有以下几个优点&#xff1a; 简单灵活&#xff0c;容易上手。…

3D数字孪生技术在工业制造中的应用

工业生产是现代工业生产和城市化建设的重要组成部分&#xff0c;工业生产逐渐批量化和自动化&#xff0c;利用数字孪生3D可视化技术对工厂生产的环境、设备、管道和仪表等元素在虚拟世界中模拟和重建&#xff0c;实现工业生产的管理、规划、设计和运营数字化可视化管理。 提高生…

利用openTCS实现车辆调度系统(五)openTCS WEB接口及扩展

上一篇介绍了RMI接口的使用&#xff0c;但是RMI接口只有java可以使用&#xff0c;不能前端直接调用。openTCS最新版本中新增了很多WEB接口&#xff0c;openTCS启动后即可调用。web接口文档地址 默认地址前缀为&#xff1a;localhost:55200/v1 例如&#xff0c;获取车辆列表。 …

JVM系统优化实践(24):ZGC(一)

您好&#xff0c;这里是「码农镖局」CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 截止到目前&#xff0c;算上ZGC&#xff0c;Java一共有九种类型的GC&#xff0c;它们分别是&#xff1a; 1、Serial GC 串行/作用于新生代/复制算法/响应速度优先/适用于单…

分享一个霓虹灯拨动开关

先看效果&#xff1a; 再看代码&#xff08;查看更多&#xff09;&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title> 霓虹灯拨动开关</title><style>* {border: 0;box-sizin…

【linux】安装pytorch3d

写在开头 不要看网上的博客安装&#xff0c;直接参考官方安装文档去安装。 坑 坑1&#xff1a;安装pytorch3d后torch.cuda用不了 使用下面的命令安装后 conda install pytorch3d会提示安装下面的包&#xff0c;注意pytorch和torchvision都是cpu版本的&#xff0c;这样就会…

以太网帧格式与吞吐量计算

以太网帧结构 帧大小的定义 以太网单个最大帧 6&#xff08;目的MAC地址&#xff09; 6&#xff08;源MAC地址&#xff09; 2&#xff08;帧类型&#xff09; 1500{IP数据包[IP头&#xff08;20&#xff09;DATA&#xff08;1480&#xff09;]} 4&#xff08;CRC校验&#xff…

【福建事业单位-资料分析】01 数学推理-基础-特征-非特征数列

【福建事业单位-资料分析】01 数学推理-基础-特征-非特征数列 一、基础数列总结 二、特征数列2.1 多重数列项数多&#xff0c;多于7项总结 2.2机械划分①小数;ab②大数字多&#xff08;三位数、四位数&#xff09;&#xff0c;达到一半或者以上总结 2.3分数数列大通分总结 2.4幂…

【MySQL】事务的多版本并发控制(MVCC)

目录 一、数据库并发的三种场景二、MVCC2.1 三个记录隐藏字段2.2 undo log&#xff08;撤销日志&#xff09;2.3 模拟MVCC2.3.1 模拟更新&#xff08;update&#xff09;2.3.1 模拟删除&#xff08;delete&#xff09;2.3.1 模拟插入&#xff08;insert&#xff09;2.3.1 模拟查…

bilibili的评论ip属地显示未知

现象 出于某些原因&#xff0c;我们在日常使用中的大部分平台都开启了IP地址显示&#xff0c;一般会显示当事人所在的地址&#xff0c;这其中就有一些奇怪的地址&#xff0c;&#xff08;在此不谈魔法&#xff09;就比如我最近在刷B站的时候&#xff0c;就在评论区发现了一些显…

C高级【day4】

思维导图&#xff1a; 写一个函数&#xff0c;获取用户的uid和gid并使用变量接收&#xff1a; #!/bin/bashfunction get_uid {my_uidid -umy_gidid -g }get_uid echo "当前用户的UID&#xff1a;$my_uid" echo "当前用户的GID&#xff1a;$my_gid"整理冒泡…