robfig/cron-go cron定时任务库架构剖析

news2024/10/6 18:28:04

Cron深度解析


思想

对于cron 这个三方库来说,他可以说是做两件事,其一是:解析cron string,生成一个定时器,达到循环时间发送信号。其二是核心(引擎):用以执行,判断,接收任务,停止cron等事情。

核心思想是面向接口,抽象开发。只有抽象才能使得哪怕九年时间过去,依然是这么简洁,普及。因为脱离了现实世界到达了柏拉图心中的理念世界理想国。

而为什么接口的实现是只要继承接口方法而不是保持对象信息呢?柏拉图的理想国认为现实世界的一切都是理念世界中各自本体的投影。那本体有哪些特征可以被用来在现实世界中与对象做判断呢?这里就涉及到唯心唯物了。主观唯心认为我与世界交互所以有了世界,如王阳明,笛卡尔,康德,佛教教义。把他们划到主观唯心也是不太对的,因为或许这就是真相,但却用两个带有偏见的名词对其做概括。之所以说主观唯心,一句诗概括就是:你未看此花时,此花与汝心同归于寂:你来看此花时,则此花颜色一时明白起来:便知此花不在你的心外。就像判断结构体是否实现接口就看是否实现了动作!因为只有动词 表示的是我在与世界做交互,互动所以有了世界。


robfig/cron at v3.0.1架构图

robfig/cron 架构图


关键位置分析

Cron 实现 Executable 接口

Executable 接口 有三个方法,Cron结构体继承。

  • 通过Start 会 启动一个并行队列
  • 通过Run 会启动一个串行队列
// Start the cron scheduler in its own go-routine, or no-op if already started.
func (c *Cron) Start() {
   if c.running {
   	return
   }
   c.running = true
   go c.run()
}

// Run the cron scheduler, or no-op if already running.
func (c *Cron) Run() {
   if c.running {
   	return
   }
   c.running = true
   c.run()
}

Cron 结构体分析

// Cron keeps track of any number of entries, invoking the associated func as
// specified by the schedule. It may be started, stopped, and the entries may
// be inspected while running.
type Cron struct {
	entries  []*Entry
	stop     chan struct{}
	add      chan *Entry
	snapshot chan []*Entry
	running  bool
	ErrorLog *log.Logger
	location *time.Location
}
  • entries:指针切片,用以执行当中的entry(即每一个任务)以及接收传进来的任务
  • stop:停止信号
  • add:接收传输管道
  • snapshot:entries 副本,打印需要

cron string 解析

在 AddJob 方法中,通过Parse 函数获取实现了Schedule 接口的结构体:SpecSchedule

func parseDescriptor(descriptor string) (Schedule, error) {
	switch descriptor {
	case "@yearly", "@annually":
		return &SpecSchedule{
			Second: 1 << seconds.min,
			Minute: 1 << minutes.min,
			Hour:   1 << hours.min,
			Dom:    1 << dom.min,
			Month:  1 << months.min,
			Dow:    all(dow),
		}, nil

	case "@monthly":
		return &SpecSchedule{
			Second: 1 << seconds.min,
			Minute: 1 << minutes.min,
			Hour:   1 << hours.min,
			Dom:    1 << dom.min,
			Month:  all(months),
			Dow:    all(dow),
		}, nil
......
}

// 该结构体实现了 Schedule 接口
type SpecSchedule struct {
	Second, Minute, Hour, Dom, Month, Dow uint64
}

引擎解析

// Run the scheduler. this is private just due to the need to synchronize
// access to the 'running' state variable.
func (c *Cron) run() {
	// Figure out the next activation times for each entry.
	now := c.now()
	for _, entry := range c.entries {
		entry.Next = entry.Schedule.Next(now)
	}

	for {
		// Determine the next entry to run.
		sort.Sort(byTime(c.entries))

		var timer *time.Timer
		if len(c.entries) == 0 || c.entries[0].Next.IsZero() {
			// If there are no entries yet, just sleep - it still handles new entries
			// and stop requests.
			timer = time.NewTimer(100000 * time.Hour)
		} else {
			timer = time.NewTimer(c.entries[0].Next.Sub(now))
		}

		for {
			select {
			case now = <-timer.C:
				now = now.In(c.location)
				// Run every entry whose next time was less than now
				for _, e := range c.entries {
					if e.Next.After(now) || e.Next.IsZero() {
						break
					}
					go c.runWithRecovery(e.Job)
					e.Prev = e.Next
					e.Next = e.Schedule.Next(now)
				}

			case newEntry := <-c.add:
				timer.Stop()
				now = c.now()
				newEntry.Next = newEntry.Schedule.Next(now)
				c.entries = append(c.entries, newEntry)

			case <-c.snapshot:
				c.snapshot <- c.entrySnapshot()
				continue

			case <-c.stop:
				timer.Stop()
				return
			}

			break
		}
	}
}

就是一个循环,循环等,循环加。

改进点

可以发现在这其中并没有写注销某一个定时任务的方法

但是想实现也是比较简单的,加一个case,监听channel,遍历 entries,找到目标,删除掉就ok了

但是既然它不加,应该是有原因的,不加的原因应该是处于经验考虑的吧?

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

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

相关文章

Spring基础篇:Spring简介

第一章&#xff1a;Spring简介 SpringIOC工厂是Spring所有特性的基础&#xff0c;Spring所有的特性都是基于IOC控制反转特性而来的。 当今微服务已经成为主流&#xff0c;微服务依赖于SpringBoot和SpringCloud&#xff0c;而SpringBoot和SpringCloud是衍生于Spring&#xff0c…

贺利坚汇编课程笔记2 访问寄存器和内存

贺利坚汇编课程笔记2 访问寄存器和内存 文章目录贺利坚汇编课程笔记2 访问寄存器和内存0201 寄存器及数据存储CPU的组成寄存器是CPU内部的信息存储单元通用寄存器--以AX为例“字”在寄存器中的存储0202 mov 和 add指令0203 确定物理地址的方法物理地址8086CPU给出物理地址的方法…

pytorch模型网页部署——Flask

一、Flask用法 Flask是python的轻量级web框架&#xff0c;可用来做简单的模型部署。Flask的基本用法如下&#xff1a; step1&#xff1a;定义Flask类的对象&#xff0c;即创建一个基于Flask的服务器 step2&#xff1a;定义公开的路由及路由对应的调用函数 step3&#xff1a…

分享新零售系统商城小程序开发制作功能介绍_商城小程序开发好处

小编主要专注于新零售系统开发商城的领域&#xff0c;新零售系统开发商业模式有哪些&#xff1a; ① 多种销售模式&#xff1a;邀请有奖、销售业绩奖、团队业绩奖、区域分红&#xff0c;分销模式等。 ② 团队协作功能&#xff1a;立即邀约分销模式&#xff0c;清楚搜索直属代…

大型ERP生产制造管理系统源码

&#x1f353;&#x1f353;【淘源码】&#xff1a;一个专业提供高品质源码免费下载的资源共享平台&#x1f353;&#x1f353; &#x1f447;&#x1f447;&#x1f447;以下是博主整理的淘源码网站内大家都比较感兴趣的一些源码&#xff0c;需要源码学习的朋友可以私信博主哦…

Exception | ShardingSphere | ShardingSphere引发的IndexOutOfBoundsException

ShardingSphere引发的IndexOutOfBoundsException一、异常二、 原因三、解决方法四、总结一、异常 ### Error querying database. Cause: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 ### The error may exist in file [D:\JetBrains\Idea\workspace\zohe\bjxz\ru…

N-gram和NNLM语言模型

背景&#xff1a; one-hot:缺点&#xff1a;1.高维稀疏&#xff0c;2.不能体现句子中词的重要性&#xff0c;3.不能体现词与词之间的关系。 embedding:1.解决了高维稀疏 tf-idf&#xff1a;2.解决了one-hot中不能体现句子中词的重要性这一特点。 语言模型&#xff1a;3.解决不能…

【20221201】【每日一题】划分字母区间

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一字母最多出现在一个片段中。 注意&#xff0c;划分结果需要满足&#xff1a;将所有划分结果按顺序连接&#xff0c;得到的字符串仍然是 s 。 返回一个表示每个字符串片段的长度的列表。 思路&…

协程Part1-boost.Coroutine.md

首先&#xff0c;在计算机科学中 routine 被定义为一系列的操作&#xff0c;多个 routine 的执行形成一个父子关系&#xff0c;并且子 routine 一定会在父 routine 结束前结束&#xff0c;也就是一个个的函数执行和嵌套执行形成了父子关系。 coroutine 也是广义上的 routine&a…

网页JS自动化脚本(五)修改文字元素的内容和大小

今天的网页打开全是灰色的,顺便缅怀一下伟人,那么我我们今天定位换成按钮文字 window.onloadfunction(){var theElementdocument.querySelector("input[typesubmit]");theElement.value"爱我中华";theElement.style"font-size:25px"; }这一次的…

提分必练!中创教育PMP全真模拟题分享来喽

湖南中创教育每日五题分享来啦&#xff0c;“日日行&#xff0c;不怕千万里&#xff1b;常常做&#xff0c;不怕千万事。”&#xff0c;每日五题我们练起来&#xff01; 1、一个项目正在实行敏捷方法&#xff0c;在迭代过程中&#xff0c;团队成员互相合作&#xff0c;解决了一…

【机器学习】核函数

核方法 核技巧 非线性分类问题是指通过利用非线性模型才能很好地进行分类的问题。如图 111 所示&#xff0c;“●”表示正样本&#xff0c;“”表示负样本&#xff0c;显然无法用直线&#xff08;线性模型&#xff09;将正负样本正确分开&#xff0c;但是可以用一条椭圆曲线&…

记一次大事务优化历程(短信发送)

问题背景 短信服务数据库连接数告警&#xff0c;grafana查看数据库连接池被打满。 问题分析 在这段时间内&#xff0c;通过链路分析&#xff0c;发现最终调用第三方短信发送服务偶然耗时过长&#xff0c;分析了原有发送逻辑的代码&#xff0c;该实现在入口send处加了事务&am…

leetcode4. 寻找两个正序数组的中位数python_二分查找和递归(困难)

题目 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&#xff09;数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。算法的时间复杂度应该为 O(log (mn)) 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,3], nums2 [2] 输出&#xff1a;2.00000 解释…

第二证券|疫情扰动叠加需求不足,11月制造业PMI回落至48%

国家统计局周三称&#xff0c;11月&#xff0c;受国内疫情点多面广频发&#xff0c;世界环境更趋复杂严峻等多重要素影响&#xff0c;我国制造业收购经理人指数&#xff08;PMI&#xff09;较上月回落1.2个百分点至48.0%。制造业PMI接连两个月低于临界点&#xff0c;制造业下行…

第4季2:并口、MIPI、LVDS的简介

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、并口的简介 1、并口的含义 并口的含义&#xff0c;可以从AR0130或OV9712的原理图中形象地理解。 如下图所示&#xff0c;AR0130采用12bit的并口向SoC传输图像数据信息&#xff0c;而SoC和AR0130…

b站黑马JavaScript的Ajax案例代码——评论列表案例

目标效果&#xff1a; 1.在表单界面输入评论人和内容&#xff0c;点击发表评论按钮&#xff0c;可以在页面下面看到自己刚刚输入的内容 2.发表评论成功之后&#xff0c;用DOM对象的reset方法&#xff1a;重置表单为其默认值 e.g.1初始状态&#xff1a;【下面的评论内容会因为…

STC 51单片机48——数码管显示外部中断次数

#include<reg52.h> #include<intrins.h> #include "math.h" #define uchar unsigned char #define uint unsigned int #define ulong unsigned long //共阴字形码表【实验】数码管实验时&#xff0c;一定要将点阵模块跳针放到VCC上&#xff01;&…

【C语言】哈夫曼树,再来一次解剖

博主&#xff1a;&#x1f44d;不许代码码上红 欢迎&#xff1a;&#x1f40b;点赞、收藏、关注、评论。 格言&#xff1a; 大鹏一日同风起&#xff0c;扶摇直上九万里。 文章目录一、定义结构1.1 定义结点权值的数据类型1.2 定义单个结点信息1.3 字符指针数组中存储的元素类…

C++ Reference: Standard C++ Library reference: Containers: list: list: list

C官网参考链接&#xff1a;https://cplusplus.com/reference/list/list/list/ 公有成员函数 <list> std::list::list C98 默认构造函数 (1) explicit list (const allocator_type& alloc allocator_type()); 填充构造函数 (2) explicit list (size_type n,…