轻量的定时任务工具 Cronicle:前篇

2023-11-03 18:59

本文主要是介绍轻量的定时任务工具 Cronicle:前篇,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本篇文章将介绍一款轻量的、自带简洁 Web UI,适用于中小团队以及个人的定时任务工具:Cronicle。

本文是关于 Cronicle 的第一篇文章,主要聊聊这个软件在容器封装下的常见问题,以及容器封装思路。

写在前面

Cronicle 自 2016 年正式开始开源,到现在已经过去了五年多了。而我第一次注意到这款软件则是在 2018 年,当时我正在为我的 HomeLab 挑选合适的定时任务工具。在过去的几年里,可以看到软件一直在细节功能上优化,目前已经做的已经比较完善了,尤其是近两年,基本没有功能上特别大的改版和变更发生。

软件除了支持基础的定时任务之外,还包含了非常多有用的功能:

  • 支持多实例搭建分布式定时任务系统
  • 具备故障自愈和服务自动迁移能力
  • 支持服务发现、以及具备自动组网的能力
  • 允许实时查看任务执行状况
  • 具备基础的插件系统,支持使用任意语言和方式来扩展能力
  • 可以针对不同时区创建定时任务
  • 可以针对降级执行时间比较长的任务做排队处理
  • 基础的任务性能图标和统计数据
  • 具备开放的 API、支持应用 API 密钥
  • 具备 Web Hook 通知能力

如果你只将它作为任务触发器使用,它的内存资源消耗将会非常小,在我重新封装的镜像中,运行超过20个小时的程序,面板展示内存使用仅 80MB 出头,而 docker stats 的结果,则连 50 MB 都不到。

轻量的资源消耗

CONTAINER ID   NAME                                    CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O    PIDS
ec4d5ab18b68   docker_cronicle_1                       5.56%     46.09MiB / 15.64GiB   0.29%     4.71MB / 20.6MB   0B / 0B      11

相比较使用传统的方式运行任务,和多数软件一样,它自带了任务执行列表,默认最低精度是 10秒,足够多数场景下的使用。

历史任务执行列表

同时,也支持针对任务输出简单的统计摘要。

简单的统计摘要

为了能够更好的使用它,我们需要对它先进行容器化封装。

如果你已经迫不及待的想开始使用它,可以跳转至至下一个章节 “在容器中使用 Cronicle”。

使用容器封装 Cronicle

第一次使用容器封装这个软件,应该是在 2018 年这个 PR 前后。随后虽然也有不少网友对这个软件进行了封装,但是都有一些不完善的地方,比如:如果你将容器进行了迁移或重建,软件将会无法运行,除非你手动进行修复;比如首次使用的时候,需要等待至少一分钟的时间才能够让软件自己组网成功,然后才可以开始使用…

所以,这篇文章里,我们就先来解决这两个问题吧。

减少 Cornicle 启动等待时间

在 jhuckaby/Cronicle/blob/master/lib/engine.js 中,有一个名为 startup 的函数,大概有一百多行,其中记录了 Cronicle 启动后需要做的事情,造成我们需要等待 60 秒才能够使用软件的逻辑主要是这部分:

...startup: function(callback) {// start cronicle servicevar self = this;this.logDebug(3, "Cronicle engine starting up");// create a few extra dirs we'll need...// archive logs daily at midnightthis.server.on('day', function () {self.archiveLogs();});// determine master server eligibilitythis.checkMasterEligibility(function () {// master mode (CLI option) -- force us to become master right awayif (self.server.config.get('master') && self.multi.eligible) self.goMaster();// reset the failover counterself.multi.lastPingReceived = Tools.timeNow(true);// startup completecallback();});
}
...

因为软件默认运行环境假设是多机的分布式环境,所以有一个比较长时间的服务发现和注册的过程。

而在本篇文章中,我们主要以单机模式运行,所以我们可以对它进行一些细微的改造,让 self.goMaster(); 这个注册当前运行实例的动作在 this.checkMasterEligibility 前执行就可以了。

考虑到 Cronicle 团队接收 PR 的时间比较漫长,为了快速实现这个功能,可以采取自制补丁,并在容器构建过程中进行“补丁应用”的方式来实现。

对程序进行适当调整之后,执行 diff -u lib/engine.js /tmp/engine.js > engine.patch 就可以轻松创建一个类似下面内容的程序补丁啦。

--- lib/engine.js	2021-06-17 19:03:36.000000000 +0000
+++ /tmp/engine.js	2021-12-04 09:50:13.000000000 +0000
@@ -152,7 +152,8 @@this.server.on('day', function() {self.archiveLogs();} );
-		
+		// for docker env
+		self.goMaster();// determine master server eligibilitythis.checkMasterEligibility( function() {// master mode (CLI option) -- force us to become master right away

而要应用补丁也很简单,只需要执行 patch -p3 < engine.patch lib/engine.js 即可。

我们先将补丁文件保存好,稍后再使用。

Cronicle 在容器中运行的其他常见问题

想要正常的运行 Cronicle ,默认情况下需要执行三条命令:

/opt/cronicle/bin/build.js dist
/opt/cronicle/bin/control.sh setup
/opt/cronicle/bin/control.sh start

前两条命令中包含了程序启动和运行过程中依赖的目录结构,以及包含了当前运行环境信息,并将其中一些信息以配置的形式进行了持久化保存。而如果我们重新创建容器环境,容器的网络、主机名都有可能产生变化,这也是为什么如果我们进行运行环境迁移,很容易遇到程序无法正常工作,需要重新部署配置程序的原因。

而第三条命令中,则是以 Daemon 的方式启动程序,因此以往有一些 Cronicle 的容器封装者会使用类似 tini 之类的程序,来完成容器封装。但其实,如果我们将容器直接以前台方式运行,就不需要这些额外的程序来做僵尸进程捕获和系统信号转发了。

当这三条命令执行完毕,软件运行所需要的目录、配置将自动初始化完毕,然后软件将运行在系统后台。

如果包含了程序的容器在运行过程中出现异常中断,软件运行时创建的 PID 文件并不会“销毁”,这同样会导致程序无法重新运行起来。

所以,为了避免和解决上面的问题,以及改进使用体验,我们需要额外的写一个小程序。

编写适合容器内使用的启动脚本

上面清楚的提到了容易发生的问题,以及问题的根源,所以编写一个用来解决这些问题的程序,也就很简单了:

#!/usr/bin/env nodeconst { existsSync, unlinkSync } = require('fs');
const { dirname } = require('path');
const { hostname, networkInterfaces } = require('os');
const StandaloneStorage = require('pixl-server-storage/standalone');if (existsSync("./logs/cronicled.pid")) unlinkSync("./logs/cronicled.pid");process.chdir(dirname(__dirname));const config = require('../conf/config.json');const storage = new StandaloneStorage(config.Storage, function (err) {if (err) throw err;const dockerHostName = (process.env['HOSTNAME'] || process.env['HOST'] || hostname()).toLowerCase();const networks = networkInterfaces();const [ip] = Object.keys(networks).filter(eth => networks[eth].filter(addr => addr.internal === false && addr.family === "IPv4").length).map(eth => networks[eth])[0];const data = {"type": "list_page","items": [{ "hostname": dockerHostName, "ip": ip.address }]};const key = "global/servers/0";storage.put(key, data, function () {storage.shutdown(function () {console.log("Record successfully saved: " + key + "\n");storage.get(key, function (_, data) {if (storage.isBinaryKey(key)) {console.log(data.toString() + "\n");} else {console.log(((typeof (data) == 'object') ? JSON.stringify(data, null, "\t") : data) + "\n")}storage.shutdown(function () {console.log("Docker Env Fixed.");require('../lib/main.js');});});});});
});

上面不到五十行代码主要做了几件事情:

  • 检测是否有之前运行程序遗留下来的 PID 文件,如果有,则清理掉,避免影响程序启动。
  • 将目前实际运行的容器环境中的 IP、主机名更新到程序配置中,避免程序不能正确启动。
  • 以前台的方式运行程序,避免再经手其他程序,保证容器足够简单。

编写容器镜像文件

这里因为 Cronicle 实际运行会使用到 shell,所以不推荐使用之前 《使用以语言为中心的容器基础镜像 distroless》 一文中提到的方式进行最小化镜像构建,仅使用普通的二阶段构建即可:

FROM node:16 AS Builder
ENV CRONICLE_VERSION=0.8.62
WORKDIR /opt/cronicle
COPY Cronicle-${CRONICLE_VERSION}.tar.gz /tmp/
RUN tar zxvf /tmp/Cronicle-${CRONICLE_VERSION}.tar.gz -C /tmp/ && \mv /tmp/Cronicle-${CRONICLE_VERSION}/* . && \rm -rf /tmp/* && \npm install --registry=https://registry.npm.taobao.org
COPY ./patches /tmp/patches
RUN patch -p3 < /tmp/patches/engine.patch lib/engine.jsFROM node:16-alpine
COPY --from=builder /opt/cronicle/ /opt/cronicle/
WORKDIR /opt/cronicleENV CRONICLE_foreground=1
ENV CRONICLE_echo=1
ENV CRONICLE_color=1
ENV debug_level=1ENV HOSTNAME=main-serverRUN node bin/build.js dist && \bin/control.sh setup
COPY docker-entrypoint.js ./bin/
CMD ["node", "bin/docker-entrypoint.js"]

因为即使是普通的二阶段构建,和基础镜像切换,也能够将软件的镜像体积由 1G 降低到 150M 不到,更加适合分发和保存。

cronicle                                      latest                              c0575a5b900b   22 hours ago    1.04GB
cronicle                                      latest                              e31626eac385   3 seconds ago        146MB

在容器中使用 Cronicle

想要让 Cronicle 快速运行起来,可以使用我预构建好的容器镜像,为了让这个镜像能够正常运行起来,我们需要两个编排文件,分别用于程序“初始化”和“正常运行”,先来编写正常运行的文件:

version: "3.6"services:cronicle:image: soulteary/cronicle:0.8.62restart: alwayshostname: cronicleports:- 3012:3012volumes:- /etc/localtime:/etc/localtime:ro- /etc/timezone:/etc/timezone:ro- ./data/data:/opt/cronicle/data- ./data/logs:/opt/cronicle/logs- ./data/plugins:/opt/cronicle/pluginsextra_hosts:- "cronicle.lab.io:0.0.0.0"environment:- TZ=Asia/Shanghaihealthcheck:test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider localhost:3012/api/app/ping || exit 1"]interval: 5stimeout: 1sretries: 3logging:driver: "json-file"options:max-size: "10m"

将上面的文件保存为 docker-compose.yml 后,继续来编写初始化运行的配置:

version: "3.6"services:cronicle:image: soulteary/cronicle:0.8.62hostname: croniclecommand: /opt/cronicle/bin/control.sh setupvolumes:- /etc/localtime:/etc/localtime:ro- /etc/timezone:/etc/timezone:ro- ./data/data:/opt/cronicle/data- ./data/logs:/opt/cronicle/logs- ./data/plugins:/opt/cronicle/pluginsenvironment:- TZ=Asia/Shanghai

将上面的文件保存为 docker-compose.init.yml,然后执行 docker-compose -f docker-compose.init.yml up,不出意外,你将会得到类似下面的内容:

cronicle_1  | 
cronicle_1  | Setup completed successfully!
cronicle_1  | This server (main) has been added as the single primary master server.
cronicle_1  | An administrator account has been created with username 'admin' and password 'admin'.
cronicle_1  | You should now be able to start the service by typing: '/opt/cronicle/bin/control.sh start'
cronicle_1  | Then, the web interface should be available at: http://main:3012/
cronicle_1  | Please allow for up to 60 seconds for the server to become master.
cronicle_1  | 
docker-cronicle_cronicle_1 exited with code 0

接着再使用 docker-compose up -d 启动服务即可,大概几秒钟后,使用 docker-compose ps 检查服务,就能够看到服务运行正常的结果了。

           Name                         Command                  State               Ports         
---------------------------------------------------------------------------------------------------
docker-cronicle_cronicle_1   docker-entrypoint.sh node  ...   Up (healthy)   0.0.0.0:3012->3012/tcp

此时,我们在浏览器中打开 localhost:3012 就能够开始使用软件啦,软件的默认账号和密码都是 admin

软件默认界面

因为软件功能界面非常直观,这里就不多针对软件的基础使用进行赘述啦。

最后

关于分布式使用、容器内灾备转移、插件编写,或许适合在下一篇关于 Cronicle 的文章中展开。文中相关代码我已经上传至 GitHub ,有需要的小伙伴可以自取。

谨以此文献给刚刚创建的技术讨论群中的小伙伴,权作抛砖引玉。

–EOF


我们有一个小小的折腾群,里面聚集了几百位喜欢折腾的小伙伴。

在不发广告的情况下,我们在里面会一起聊聊软硬件、HomeLab、编程上的一些问题,也会在群里不定期的分享一些技术沙龙的资料。

喜欢折腾的小伙伴欢迎扫码添加好友。(添加好友,请备注实名,注明来源和目的,否则不会通过审核)

关于折腾群入群的那些事


如果你觉得内容还算实用,欢迎点赞分享给你的朋友,在此谢过。


本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)

本文作者: 苏洋

创建时间: 2021年12月05日
统计字数: 4412字
阅读时间: 9分钟阅读
本文链接: https://soulteary.com/2021/12/05/cronicle-a-lightweight-tool-for-timed-tasks-part-1.html

这篇关于轻量的定时任务工具 Cronicle:前篇的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/340234

相关文章

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

高效录音转文字:2024年四大工具精选!

在快节奏的工作生活中,能够快速将录音转换成文字是一项非常实用的能力。特别是在需要记录会议纪要、讲座内容或者是采访素材的时候,一款优秀的在线录音转文字工具能派上大用场。以下推荐几个好用的录音转文字工具! 365在线转文字 直达链接:https://www.pdf365.cn/ 365在线转文字是一款提供在线录音转文字服务的工具,它以其高效、便捷的特点受到用户的青睐。用户无需下载安装任何软件,只

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

超强的截图工具:PixPin

你是否还在为寻找一款功能强大、操作简便的截图工具而烦恼?市面上那么多工具,常常让人无从选择。今天,想给大家安利一款神器——PixPin,一款真正解放双手的截图工具。 想象一下,你只需要按下快捷键就能轻松完成多种截图任务,还能快速编辑、标注甚至保存多种格式的图片。这款工具能满足这些需求吗? PixPin不仅支持全屏、窗口、区域截图等基础功能,它还可以进行延时截图,让你捕捉到每个关键画面。不仅如此

ActiveMQ—消息特性(延迟和定时消息投递)

ActiveMQ消息特性:延迟和定时消息投递(Delay and Schedule Message Delivery) 转自:http://blog.csdn.net/kimmking/article/details/8443872 有时候我们不希望消息马上被broker投递出去,而是想要消息60秒以后发给消费者,或者我们想让消息没隔一定时间投递一次,一共投递指定的次数。。。 类似

PR曲线——一个更敏感的性能评估工具

在不均衡数据集的情况下,精确率-召回率(Precision-Recall, PR)曲线是一种非常有用的工具,因为它提供了比传统的ROC曲线更准确的性能评估。以下是PR曲线在不均衡数据情况下的一些作用: 关注少数类:在不均衡数据集中,少数类的样本数量远少于多数类。PR曲线通过关注少数类(通常是正类)的性能来弥补这一点,因为它直接评估模型在识别正类方面的能力。 精确率与召回率的平衡:精确率(Pr

husky 工具配置代码检查工作流:提交代码至仓库前做代码检查

提示:这篇博客以我前两篇博客作为先修知识,请大家先去看看我前两篇博客 博客指路:前端 ESlint 代码规范及修复代码规范错误-CSDN博客前端 Vue3 项目开发—— ESLint & prettier 配置代码风格-CSDN博客 husky 工具配置代码检查工作流的作用 在工作中,我们经常需要将写好的代码提交至代码仓库 但是由于程序员疏忽而将不规范的代码提交至仓库,显然是不合理的 所

10个好用的AI写作工具【亲测免费】

1. 光速写作 传送入口:http://u3v.cn/6hXWYa AI打工神器,一键生成文章&ppt 2. 讯飞写作 传送入口:http://m6z.cn/5ODiSw 3. 讯飞绘文 传送入口:https://turbodesk.xfyun.cn/?channelid=gj3 4. AI排版助手 传送入口:http://m6z.cn/6ppnPn 5. Kim

分享5款免费录屏的工具,搞定网课不怕错过!

虽然现在学生们不怎么上网课, 但是对于上班族或者是没有办法到学校参加课程的人来说,网课还是很重要的,今天,我就来跟大家分享一下我用过的几款录屏软件=,看看它们在录制网课时的表现如何。 福昕录屏大师 网址:https://www.foxitsoftware.cn/REC/ 这款软件给我的第一印象就是界面简洁,操作起来很直观。它支持全屏录制,也支持区域录制,这对于我这种需要同时录制PPT和老师讲

生信圆桌x生信分析平台:助力生物信息学研究的综合工具

介绍 少走弯路,高效分析;了解生信云,访问 【生信圆桌x生信专用云服务器】 : www.tebteb.cc 生物信息学的迅速发展催生了众多生信分析平台,这些平台通过集成各种生物信息学工具和算法,极大地简化了数据处理和分析流程,使研究人员能够更高效地从海量生物数据中提取有价值的信息。这些平台通常具备友好的用户界面和强大的计算能力,支持不同类型的生物数据分析,如基因组、转录组、蛋白质组等。