【个人博客搭建】(18)使用Quartz.NET 定时备份数据库

ops/2024/10/19 9:35:03/

Quartz.NET在系统主要承担的一些关键功能:

  • 任务调度:Quartz.NET 允许开发人员创建、调度和管理定时任务,支持简单触发器和Cron表达式等多样化的触发策略。
  • 灵活性:Quartz.NET 提供了灵活的任务安排机制,不仅支持基于时间间隔的重复执行,还能根据特定日期、时间等信息来安排任务执行。
  • 高可用性:对于企业级应用,Quartz.NET 提供了路由支持、Group管理以及持久化机制,确保任务的高可用性和系统的稳定运行。
  • 集成性:Quartz.NET 可以与ASP.NET Core应用程序整合,通过Quartz.Extensions.Hosting包实现对后台任务的直接支持。

Quartz.NET 可以在博客系统中承担以下功能:

  1. 内容发布管理:可以设置定时任务来自动发布文章,例如在特定时间发布博文或定期发布一系列教程。
  2. 数据备份:可以安排定期执行数据库备份的任务,确保博客数据的安全。
  3. 定期维护:可以执行如清理垃圾文件、更新插件和系统等定期维护任务。
  4. 邮件通知:可以实现定时向订阅者发送邮件通知,比如最新文章的推送或者定期通讯。
  5. 访问统计分析:可以定时生成博客访问报告,分析访问量、用户行为等信息。
  6. 评论和回复处理:可以设置定时检查评论和回复的任务,对不良信息进行过滤或标记。
  7. 广告轮换:可以安排广告内容的自动更新和轮换。
  8. 社交媒体同步:可以安排任务将新内容自动分享到社交媒体平台。
  9. 反垃圾邮件措施:通过定时监控和清理,减少垃圾评论和留言。
  10. 用户体验优化:可以通过定期执行A/B测试或其他优化工作来改善用户体验。
  11. 搜索引擎优化(SEO):定期更新网站的SEO策略和关键字,以提高搜索引擎排名。
  12. 监控与告警:监控系统性能和可用性,并在出现问题时发送告警。

总的来说,Quartz.NET 的灵活性和强大功能使其成为博客系统中自动化管理任务的理想选择。通过继承 IJob 接口,你可以创建各种类型的作业来满足不同的需求。

这里,我们要处理的就是数据库备份的功能。

1、 安装 NuGet 包: Quartz.NET

2、创建一个作业类:创建一个继承自 IJob 接口的类,实现 Execute 方法,该方法将在指定的时间执行数据库备份操作。

(这里建议在解决方案下边新建一个类库Tasks)

using Quartz;
using System.Threading.Tasks;public class BackupDatabaseJob : IJob
{public Task Execute(IJobExecutionContext context){// 在这里执行数据库备份操作// ...return Task.CompletedTask;}
}

3、 配置。 在你的应用程序中,配置 Quartz.NET 以使用你的作业类和触发器。

using Quartz;
using Quartz.Impl;public static async Task Main()
{// 创建调度器工厂StdSchedulerFactory factory = new StdSchedulerFactory();// 从工厂获取调度器实例IScheduler scheduler = await factory.GetScheduler();// 启动调度器await scheduler.Start();// 定义作业并将其与我们的作业类关联起来IJobDetail job = JobBuilder.Create<BackupDatabaseJob>().WithIdentity("backupJob").Build();// 定义触发器,设置作业执行的时间间隔ITrigger trigger = TriggerBuilder.Create().WithIdentity("backupTrigger").StartNow() // 立即开始.WithSimpleSchedule(x => x.WithIntervalInHours(24) // 每24小时执行一次.RepeatForever()) // 无限循环.Build();// 将作业和触发器添加到调度器中await scheduler.ScheduleJob(job, trigger);
}

 4、运行

5、待测试功能

        在执行任务那,我们需要引用其他方法,所以建议单独用一个类库项目存储

--------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------

【二】:续:

下边是项目中使用的简单案例:

1、创建一个帮助类

public class QuartzHelper{private static IScheduler _scheduler;/// <summary>/// 初始化调度器/// </summary>/// <returns></returns>public static async Task InitializeAsync(){if (_scheduler == null){var factory = new StdSchedulerFactory();_scheduler = await factory.GetScheduler();await _scheduler.Start();}}public static async Task<string> AddJobAsync<T>(string jobName, string groupName, TimeSpan interval) where T : IJob{if (_scheduler == null){await InitializeAsync();}//var job = JobBuilder.Create<T>().WithIdentity(jobName, groupName).Build();//var trigger = TriggerBuilder.Create().WithIdentity($"{jobName}-trigger", groupName)//    .StartNow()//    .WithSimpleSchedule(x => x.WithInterval(interval).RepeatForever())//    .Build();//替换为://反射执行程序集var jobClassName = typeof(T).Name;var baseType = typeof(IJob);var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;var referencedAssemblies = System.IO.Directory.GetFiles(path, "plateau.poetize.blog.Tasks.dll").Select(Assembly.LoadFrom).ToArray();var jobType = referencedAssemblies.SelectMany(a => a.DefinedTypes).Select(type => type.AsType()).Where(x => x.Name == jobClassName).First();string times = DateTime.Now.ToString("yyyyMMddHHmmssfff");//1、任务:IJobDetail job = new JobDetailImpl(times, groupName, jobType);//任务名称,任务组//2、触发器ITrigger trigger = TriggerBuilder.Create().WithIdentity(jobName + "-Trigger" + "-" + times, groupName)//触发器名称,任务组.StartNow() // 立即开始(后续有web界面时,不建议立即执行,每个操作都建议独立).WithSimpleSchedule(x => x.WithIntervalInHours(12) // 每12小时执行一次.RepeatForever()) // 无限循环.Build();//3、参数(可无)job.JobDataMap.Add("JobParam", "参数:......");//共享的,也可以更改值job.JobDataMap.Add("JobRunNum", 1);//具体执行的时候可以更改值,打印//4、调度器var v = await _scheduler.ScheduleJob(job, trigger);Console.WriteLine("任务开始成功");return "任务开始成功";}public static async Task RemoveJobAsync(string jobName, string groupName){if (_scheduler == null){return;}await _scheduler.DeleteJob(new JobKey(jobName, groupName));}public static async Task StartAsync(){if (_scheduler == null){await InitializeAsync();}await _scheduler.Start();}public static async Task StopAsync(){if (_scheduler == null){return;}await _scheduler.Shutdown();}}

2、Job任务类:

public class BackupDatabaseJob : IJob{/// <summary>/// 执行/// </summary>/// <param name="context">上下文</param>/// <returns></returns>public Task Execute(IJobExecutionContext context){using (var serviceScope = MyApp.Instance.CreateScope()){var server = serviceScope.ServiceProvider.GetService<IMyJobService>();var list = server.BackupDatabase();//获取传递过来的参数JobDataMap data = context.JobDetail.JobDataMap;int jobRunNum = data.GetInt("JobRunNum");string jobParam = data.GetString("JobParam");///Console.WriteLine($"BackupDatabaseJob 执行 {DateTime.Now.ToString()}");Console.WriteLine($"【JobRunNum】 :{jobRunNum}");Console.WriteLine($"【JobParam】: 执行 {jobParam}");修改值//jobRunNum++;//data["JobRunNum"] = jobRunNum; // 修改 JobDataMap 中的值}return Task.CompletedTask;}}

        上边与之前的差距主要就是在使用

        

//引入命名空间(nuget包)
using Microsoft.Extensions.DependencyInjection;//代码
using (var serviceScope = MyApp.Instance.CreateScope()) 

        这里的MyApp是一个静态类

public static class MyApp
{public static IServiceProvider Instance { get; set; }}

        这里值的赋值在入口文件中进行:

//写入静态类供全局获取
MyApp.Instance = app.Services;

3、注入服务:

//注入服务
builder.Services.AddTransient<IMyJobService, MyJobService>();
builder.Services.AddTransient<ISchedulerCenter, SchedulerCenterServer>();
//注入任务
builder.Services.AddTransient(typeof(BackupDatabaseJob));

        注入服务可以反射循环注入。 

4、运行:

await QuartzHelper.AddJobAsync<BackupDatabaseJob>("myJob_BackupDatabaseJob", "myGroup_BackupDatabaseJob", TimeSpan.FromHours(24));

5、效果:

6、拓展:

        6.1、目前使用的方式都是代码固定的,可创建模型进行参数化 

        6.2、后续还要做一个Web的可视化操作。

        6.3、因为异步,如果多层可能会得不到实际的返回值。

        6.4、共享参数的读取、赋值。记录日志等

        6.5、并发问题:(例如程序需要执行2秒,但是任务是1秒一次)。实际的执行时间大于给定任务时间。需要设置,然后会根据实际的任务时间进行循环。


http://www.ppmy.cn/ops/38866.html

相关文章

最新版rancher环境配置安装和集群搭建详细教程记录

&#x1f680; 作者 &#xff1a;“二当家-小D” &#x1f680; 博主简介&#xff1a;⭐前荔枝FM架构师、阿里资深工程师||曾任职于阿里巴巴担任多个项目负责人&#xff0c;8年开发架构经验&#xff0c;精通java,擅长分布式高并发架构,自动化压力测试&#xff0c;微服务容器化k…

9.为什么有时候会“烫烫烫”——之函数栈桢

目录 1. 什么是函数栈帧 2. 理解函数栈帧能解决什么问题呢&#xff1f; 3. 函数栈帧的创建和销毁解析 3.1 什么是栈&#xff1f; 3.2 认识相关寄存器和汇编指令 3.3 解析函数栈帧的创建和销毁 小知识&#xff1a;烫烫烫~ Q&A 1. 什么是函数栈帧 我们在写C语言代码…

React 基础案例

React的特点&#xff1a; 1、声明式编程 2、组件化开发 3、多平台适配yuan 原生实现&#xff1a; <h2 class"title"></h2><button class"btn">改变文本</button><script>let msg "Hello World";const titleEl d…

NIO BIO AIO详解

BIO: 同步阻塞I/O&#xff0c;是JDK1.4之前的传统IO模型。 线程发起IO请求后&#xff0c;一直阻塞&#xff0c;直到缓冲区数据就绪后&#xff0c;再进入下一步操作。 NIO:同步非阻塞IO&#xff0c;当线程发起IO请求后&#xff0c;不需要阻塞&#xff0c;会立即返回。用户线程不…

初识kafka

一、发布与订阅系统 发布与订阅系统&#xff1a;数据的发送者不会直接把消息发送给接收者&#xff1b;发布者以某种方式对消息进行分类&#xff0c;接收者通过订阅他们来接收特定类型的消息。发布与订阅系统也是事件驱动型程序的关键组件 二、初识Kafka kafka是一款基于发布…

“漫画之家”|基于Springboot+vue的“漫画之家”系统(源码+数据库+文档)

“漫画之家”系统 目录 基于Springbootvue的“漫画之家”系统 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2后台模块 5.2.1管理员功能模块 5.2.2用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&a…

vector实战

vector声明 初始化 获取数据 修改元素值 追加元素 遍历 定义二维的vector 二维vector遍历 #include <iostream> #include <vector>using namespace std;int main(){// vector 声明vector<string> name_vector;// vector 初始化vector<int> sco…

【Leetcode】55- 跳跃游戏

问题简述 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#…