无需Get更多技能,快速打造一个可持久化的任务调度

本文介绍如何利用TopShelf和Quartz在.NET中构建Windows服务,实现定时任务调度。包括服务框架搭建、任务调度配置及具体代码实现。

    项目总是很忙,忙里偷闲还是要总结一下,前一段时间,由于项目中需要,我们需要很多定时汇总数据的情况,项目初期主要使用sql server 计划任务实现对数据的汇总与统计,但是开发到一定时间内,需求提出了很多自动任务的功能,很多不是能够在SQL Server中进行解决的,例如订单关闭前多少分钟内发短信与邮箱告诉用户,程序层面每天汇总错误日志发送至运维邮箱等,针对目前情况,简单上网查了一下,决定使用TopShelf + Quartz 进行自动服务与任务调度,关于这两项的介绍也很多了,废话不多说,直接上代码:

  • 项目结构图如下:

 

任务调度与任务实现实质是两个完全不同的东西,所以自动服务于Job执行是应该分开的,所以任务创建时应该吧Job加载到任务调度工程,最后告诉调度工厂,可以开始执行任务之后,调度工厂会进行扫描Job,加载到内存中挨个执行。

  • IAutoService: 主要是声明自动服务的接口模式,标记了服务的名称,启动时的加载等,统一由抽象类AutoServcieBase实现。

 1  public interface IAutoService
 2     {
 3         /// <summary>
 4         /// 服务名称
 5         /// </summary>
 6         string ServiceName { get; }
 7 
 8         /// <summary>
 9         /// 启动方法
10         /// </summary>
11         void Start();
12 
13         /// <summary>
14         /// 是否启用
15         /// </summary>
16         bool IsEnable { get; }
17     }
  • AutoServiceBase: 抽象类实现接口原则,规范自动任务的可选参数,统一封装调用,定义抽象方法与属性,子类重写。

 1   public abstract class AutoServiceBase : IAutoService
 2     {
 3         public IQuartzConfiguration QuartzConfiguration { get; set; }
 4 
 5         public IQuartzScheduleJobManager QuartzScheduleJobManager { get; set; }
 6 
 7         public const string ServiceGroupName = "AutoService.Groups";
 8 
 9         /// <summary>
10         /// 服务名称
11         /// </summary>
12         public virtual string ServiceName { get { return "服务启动..."; } }
13 
14         /// <summary>
15         /// 任务调度
16         /// </summary>
17         public virtual Action<TriggerBuilder> ConfigureTrigger { get; }
18 
19         public virtual bool IsEnable { get { return true; } }
20 
21         /// <summary>
22         /// 获取服务方法名称
23         /// </summary>
24         /// <returns></returns>
25         public abstract string GetServiceIdentiy();
26 
27         /// <summary>
28         /// 启动任务
29         /// </summary>
30         public abstract void Start();
31 
32     }

定义好基础服务后,接下来我们就要使用TopShelf搭建一个属于我们自己的windows service了,代码如下:

class Program
      {
         static void Main(string[] args)
         {
             HostFactory.Run(x =>
             {
                 x.Service<Service>(s =>
                 {
                     s.ConstructUsing(name => new Service());
                     s.WhenStarted(tc => tc.Start());
                     s.WhenStopped(tc => tc.Stop());
                     s.WhenShutdown(tc => tc.Shutdown());
                 });
                 x.RunAsLocalSystem();
                 x.SetDescription("服务集合,包含自动化消息,响应队列的领域事件");
                 x.SetDisplayName("Test.Services");
                 x.SetServiceName("Test.Services");
             });
         }
     }

  topshelf是一个很简单就能创建service的工具,它开源在GitHub TopShelf上,是一款快速搭建mono与windows service ,在编写好我们的服务代码,只需简单地启动代码,就能创建一个持久化的服务,不过想要兼容在Mono上也是非常简单,只需加入如下一句代码即可。

 x.UseLinuxIfAvailable(); 

 在我们的项目中windows service不仅仅是任务调度的寄宿形式,同时也是我们Event Store,对DDD感兴趣的同学可以了解CQRS中SAGA模式中事件消费的形式,这个不在本文讨论。

创建好我们的基础服务后,接下来就是对任务调度工厂的设置,任务调度简单来看,我们往往要使用事件监听,任务总调度工厂等等,这里Quartz很好的集成了这些,我们只需进行简单的改造就能够实现如上功能。

  • QuartzScheduleJobManager:实现任务调度管理,在这里可以对总任务调度工厂进行启动,停止,加载Job等

 1 public interface IQuartzScheduleJobManager
 2     { 
 3         /// <summary>
 4         /// 增加任务与任务调度到任务工厂
 5         /// </summary>
 6         /// <typeparam name="TJob"></typeparam>
 7         /// <param name="configureJob">任务</param>
 8         /// <param name="configureTrigger">任务调度</param>
 9         /// <returns></returns>
10         Task ScheduleAsync<TJob>(Action<JobBuilder> configureJob, Action<TriggerBuilder> configureTrigger) where TJob : IJob;
11 
12         /// <summary>
13         /// 启动任务
14         /// </summary>
15         void Start();
16 
17         /// <summary>
18         /// 等待任务完成并停止任务
19         /// </summary>
20         void ShutDown();
21     }
22 
23 public class QuartzScheduleJobManager : IQuartzScheduleJobManager
24     {
25         private readonly IQuartzConfiguration _quartzConfiguration;
26 
27         public QuartzScheduleJobManager(
28             IQuartzConfiguration quartzConfiguration)
29         {
30             _quartzConfiguration = quartzConfiguration;
31         }
32 
33         /// <summary>
34         /// 增加任务与任务调度到任务工厂
35         /// </summary>
36         /// <typeparam name="TJob"></typeparam>
37         /// <param name="configureJob">任务</param>
38         /// <param name="configureTrigger">任务调度</param>
39         /// <returns></returns>
40         public Task ScheduleAsync<TJob>(Action<JobBuilder> configureJob, Action<TriggerBuilder> configureTrigger)
41             where TJob : IJob
42         {
43             var jobToBuild = JobBuilder.Create<TJob>();
44             configureJob(jobToBuild);
45             var job = jobToBuild.Build();
46 
47             var triggerToBuild = TriggerBuilder.Create();
48             configureTrigger(triggerToBuild);
49             var trigger = triggerToBuild.Build();
50 
51             _quartzConfiguration.Scheduler.ScheduleJob(job, trigger);
52 
53             return Task.FromResult(0);
54         }
55 
56         /// <summary>
57         /// 启动任务
58         /// </summary>
59         public void Start()
60         {
61             //启动任务调度框架
62             if (!_quartzConfiguration.Scheduler.IsStarted)
63             {
64                 _quartzConfiguration.Scheduler.Start();
65             }
66         }
67 
68         /// <summary>
69         /// 等待任务完成并停止任务
70         /// </summary>
71         public void ShutDown()
72         {
73             if (_quartzConfiguration.Scheduler.IsStarted && !_quartzConfiguration.Scheduler.IsShutdown)
74             {
75                 _quartzConfiguration.Scheduler.Shutdown();
76             }
77         }
78     }

IQuartzConfiguration是对IScheduler的一个简单封装,创建默认的调度程序:

1 public class QuartzConfiguration : IQuartzConfiguration
2     {
3         public IScheduler Scheduler => StdSchedulerFactory.GetDefaultScheduler();
4     }

 接下来就是任务监听,Quartz提供了一个很好的扩展,我们只需实现IJobListener接口即可,包含如下多个方法体:

  1. JobExecutionVetoed
  2. JobToBeExecuted
  3. JobWasExecuted

查看字面意思,我们就能很好理解就是对每一个job在执行中的阶段所对应的事件,方法体内给出IJobExecutionContext当前执行的上下文,通过上下文我们可以输出许多我们想要的东西,例如当前执行Job的Name,执行时间,等等,也提供了JobExecutionException等异常信息,可以监控Job执行过程中发生的错误,很方便。

好了在我们的寄宿服务,与基础服务搭建完毕后,接下来就是要实现在业务系统中我们自身的逻辑结构了,核心程序类Servcie.cs,在service中我们需要将我们如上的配置进行加载,并同时扫描我们业务系统中的定时服务类,挨个进行启动,代码如下:

 

public class Service
    {
        /// <summary>
        /// 任务调度框架
        /// </summary>
        private IQuartzScheduleJobManager QuartzScheduleJobManager
        {
            get
            {
                return IocManager.Instance.Resolve<IQuartzScheduleJobManager>();
            }
        }

        /// <summary>
        /// 任务调度配置
        /// </summary>
        public IQuartzConfiguration QuartzConfiguration
        {
            get
            {
                return IocManager.Instance.Resolve<IQuartzConfiguration>();
            }
        }

        public Service()
        {
            try
            {
//注册我们的任务调度程序配置
IocManager.Register<IQuartzConfiguration, QuartzConfiguration>();
//注册任务监听程序到Ioc
 IocManager.Register<IJobListener, QuartzJobListener>();
//声明一个接口可以被多个实例实现 IocManager.IocContainer.Kernel.Resolver.AddSubResolver(
new ArrayResolver(TongTongMallBootstrapper.IocManager.IocContainer.Kernel, true)); } catch (Exception ex) { LogHelper.LogException(ex); } }
//设置我们的配置项
public void QuartzConfigurationInitialize() { //Job映射工厂 QuartzConfiguration.Scheduler.JobFactory = new QuartzJobFactory(IocManager.Instance); //Job 监听配置 QuartzConfiguration.Scheduler.ListenerManager.AddJobListener(IocManager.Instance.Resolve<IJobListener>()); } /// <summary> /// 基础类服务 /// </summary> public void Start() { //订阅各项自动服务 IocManager.Instance.IocContainer.Register(Classes.FromThisAssembly().BasedOn<IAutoService>().WithService.Base()); QuartzConfigurationInitialize(); RegisterService(); } /// <summary> /// 停止自动服务 /// </summary> public void Stop() { QuartzScheduleJobManager.ShutDown(); } /// <summary> /// 结束自动服务 /// </summary> public void Shutdown() { TongTongMallBootstrapper.Dispose(); QuartzScheduleJobManager.ShutDown(); } /// <summary> /// 注册服务 /// </summary> /// <param name="args"></param> public void RegisterService() { foreach (var service in IocManager.Instance.IocContainer.ResolveAll<IAutoService>()) { if (service.IsEnable) { LogHelper.Logger.Debug($"{service.ServiceName}服务正在启动中..."); service.Start(); } } LogHelper.Logger.Debug($"任务总调度工厂启动!"); QuartzScheduleJobManager.Start(); } }

 在系统中我们主要使用了IOC进行了一个服务的自动扫描与切入,在服务配置完毕后,接下来我们只需定义业务相关的自动服务即可,通过继承我们的抽象类AutoServiceBase,接下来就很方便的打造每一个自动任务调度了,而关于Quartz的任务调度形式与时间配置,不是本文的重点介绍内容,就不在详说,不过在任务调度中我们也可以实现很多自定义的时间调度模式,例如自定义的节假日,或者每周一执行任务调度都可以,这个需要进行进一步编码实现。

由于公司方面,代码就不在给连接资源下载了,代码给出只是思路,当然在这里面还可以有更多的扩展,而本文只是方便快速上手为第一原则,文章有写的不当的地方,请及时指出,如本文对您有所帮助,也请点个推荐,您的肯定也是是我最大的动力。thanks

    

转载于:https://www.cnblogs.com/doNetTom/p/6442201.html

<think>嗯,用户这次问的是自动化运维平台中任务调度子系统的设计方法,看来ta对运维自动化有深入研究的需求。之前我们讨论过配置管理的步骤,现在ta想聚焦在任务调度这个更具体的子系统上,说明ta可能正在设计或优化运维平台。用户引用了三篇文献,但实际需求很明确:要一个落地的任务调度子系统设计方案。第一篇关于Python分布式计算集群调度的引用很有价值,正好能用于任务调度的核心模块设计;第二篇IFTTT模型可以借鉴到故障处理联动;第三篇云平台自动化部署的经验对任务执行引擎有参考意义。用户应该是运维架构师或技术负责人,需要兼顾理论和实践。ta的问题非常专业,说明对系统设计有丰富经验。考虑到运维系统的复杂性,我会从架构设计开始层层展开,重点突出可扩展性和容错性——这两点在生产环境中至关重要。设计这类系统时最关键的矛盾是:既要支持多样化的运维任务(批处理、定时、流式等),又要保证高可靠性。因此分层架构是必然选择:调度层专注策略,执行层处理具体操作,控制层协调全局。每个层级都需要独立的容错机制,比如调度器用主从热备,执行器用心跳监测。Python作为实现语言的优势在于丰富的生态(Celery、APScheduler等),但JVM系(Java/Scala)在分布式协调上更成熟。考虑到用户引用的是Python方案,我会侧重Python技术栈,同时对比其他选项供ta权衡。调度算法部分需要数学建模:设任务集合为$T$,资源集合为$R$,优化目标是最小化完成时间$\min(\max_{t_i\inT}C_{t_i})$,约束条件包括资源容量$\sumr_j\leqR_k$。这类背包问题通常用贪心算法+权重调度解决。故障恢复策略必须考虑雪崩效应,所以采用指数退避重试(backoff=$\beta\times2^n$)比固定间隔更安全。所有关键点都会配上行业验证过的方案,比如Netflix的ChaosMonkey思想,避免纸上谈兵。最后生成的问题都瞄准落地难点:分布式事务和状态同步是实际部署时最容易踩坑的地方。用户下次可能会追问这些细节,提前准备好延伸方向。</think>以下是自动化运维平台中**任务调度子系统**的设计方案与架构详解,结合分布式计算、故障自动处理及云平台部署技术,重点突出高可用性、扩展性和自动化能力: --- ### 一、任务调度子系统核心设计目标 1. **高可用性**:99.95%+ SLA,支持故障自动转移 2. **弹性扩展**:动态应对任务负载波动(如突发批量作业) 3. **策略多样性**:支持定时、依赖触发、事件驱动等调度模式 4. **可视化管控**:全链路任务状态追踪与干预能力 5. **自动化容错**:基于规则引擎的故障自愈(参考引用[2]的IFTTT模型) --- ### 二、系统架构设计(分层模型) ```mermaid graph LR A[调度控制层] --> B[任务队列层] B --> C[分布式执行层] C --> D[基础设施层] ``` #### 1. **调度控制层(大脑)** - **功能组件**: - **策略引擎**:解析任务调度规则(Cron表达式、DAG依赖等) - **状态机引擎**:管理任务生命周期(如`Pending→Running→Succeed/Failed`) - **仲裁器(HA Controller)**:基于Raft协议实现多活调度节点选举 $$ \text{Leader选举条件:} \quad \exists n \in \text{Nodes} \mid \text{Vote}_n > \lfloor \frac{\text{N}_{total}}{2} \rfloor $$ - **规则引擎**:集成IFTTT模型实现故障自动处理(引用[2]) ```python # 伪代码示例:磁盘超阈值自动清理 if monitor.get_disk_usage() > 90%: scheduler.execute_task(clean_log_task, target_host) ``` #### 2. **任务队列层(中枢神经)** - **技术选型**: | 队列类型 | 应用场景 | 推荐方案 | |----------------|---------------------------|-------------------| | 优先级队列 | 紧急故障修复任务 | RabbitMQ+优先级插件 | | 延迟队列 | 定时任务 | Redis ZSET | | 持久化队列 | 关键任务防丢失 | Kafka/Pulsar | - **队列监控**:实时计算积压任务数告警 $$ \text{Backlog Risk} = \begin{cases} \text{紧急} & \text{if } \frac{\text{待处理任务}}{\text{处理能力}} > 3 \\ \text{警告} & \text{if } > 1.5 \end{cases} $$ #### 3. **分布式执行层(四肢)** - **执行单元设计**: ```plaintext +---------------------+ | 执行器集群 | | +-----------------+ | | | 任务槽(Task Slot)|←→ 资源隔离 | | - CPU/Mem隔离 | | | | - 超时熔断 | | | +-----------------+ | +----------↑----------+ └── 自动注册到ZooKeeper ``` - **关键机制**: - **心跳检测**:执行器每5s上报状态,超时则重新调度任务 - **负载均衡**:基于资源利用率的动态分配算法 $$ \text{Score}_{node} = \alpha \cdot \text{CPU}_{free} + \beta \cdot \text{Mem}_{free} \quad (\alpha+\beta=1) $$ - **结果回传**:异步写入MySQL+Elasticsearch双存储 #### 4. **基础设施层(骨骼)** - **资源调度**:对接Kubernetes API实现容器化任务运行(引用[3]) - **混合云支持**: ```mermaid graph TB Task -->|公有云| AWS_Batch Task -->|私有云| K8s_Cluster Task -->|边缘节点| Edge_Agent ``` --- ### 三、核心工作流程(以定时任务为例) ```mermaid sequenceDiagram participant 用户 participant 调度API participant 任务队列 participant 执行器 用户->>调度API: 提交任务(cron="0 * * * *") 调度API->>任务队列: 写入延迟队列(execute_time=整点) loop 每分钟检查 任务队列->>调度API: 到达执行时间的任务 end 调度API->>执行器: 分配任务(负载最低节点) 执行器->>基础设施: 执行命令/脚本 执行器-->>调度API: 实时状态更新 调度API-->>用户: 推送邮件/钉钉通知 ``` --- ### 四、关键技术实现方案 1. **分布式锁**: ```python # 使用Redis Redlock防止重复调度 lock = redlock.Redlock([redis_conn], retry_count=3) if lock.acquire(resource="task_123", ttl=30000): execute_task() ``` 2. **任务分片**(大数据场景): ```python # 将10万条数据分片处理 shards = [data[i:i+1000] for i in range(0, len(data), 1000)] for shard in shards: scheduler.add_task(process_shard, shard) ``` 3. **故障自愈**(结合引用[2]): ```plaintext 监控告警 → 触发调度规则 → 执行预设动作(重启/迁移/扩容) ``` 4. **云原生部署**(引用[3]): - Helm Chart打包调度组件 - 通过Operator实现自恢复集群 --- ### 五、性能优化关键点 1. **调度吞吐量**: - 批量任务合并处理(减少DB写入次数) - 使用Protocol Buffers序列化任务数据 2. **资源利用率**: - 基于历史数据的预测调度 $$ \text{Predicted Load}_{t} = \frac{1}{n} \sum_{i=1}^{n} \text{Load}_{t-i} + \alpha \cdot \text{trend} $$ 3. **跨机房延迟**: - 部署区域化调度集群(如Azone调度器仅管理本机房资源) --- ### 六、监控指标体系 | 类别 | 核心指标 | 告警阈值 | |--------------|---------------------------|------------------| | 调度性能 | 任务派发延迟 | >500ms | | 资源健康度 | 执行器CPU/Mem使用率 | >85%持续5分钟 | | 系统可靠性 | 任务失败率 | 24h内>1% | | 队列健康度 | Pending任务积压量 | >1000 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值