用Go实现一个跨语言的定期任务调度器(1)

完整目录:

由于管理的服务越来越多, 导致机器上的定期任务越来越多, 然后任务越多, 问题也很多

  • 每个人写的脚本语言可能都不一样, 有人写的python, 有人写的shell, 有人写的go, 然后python的版本也不统一
  • 每个脚本的日志, 执行结果等信息, 有的人存在本地, 有的人写的发邮件
  • 每个脚本没有版本管理
  • 没有一个统一的平台查看我们到底有多少个定期任务, 跑在什么服务器上, 是用做什么功能

所以决定自己用Go写一个跨语言的定期任务调度器, 需要实现的功能

  • 跨语言
  • 可以存任务的输出日志, 记录任务的执行结果
  • 可以让用户在前端手动的执行任务
  • 可以暂停任务, 删除任务

第一个要解决的问题, 就是跨语言问题

如果放在服务器上直接运行任务, 那么带来的问题非常多

  • 我们需要针对不同的任务, 创建非常多文件夹, 如果任务是python, 那么我们还需要创建很多虚拟环境, 然后安装不同任务的依赖
  • 如果涉及到任务的删除, 那么需要直接操作服务器去删除文件夹
  • 我们需要在服务器上安装很多语言环境, 比如go, python等等

所以思考下来, 决定用Docker来实现任务的执行, 好处如下

  • 服务器上不需要安装任何语言环境
  • 执行任务不会影响到宿主机, 不会有太大的安全风险

坏处是shell脚本的定期任务放在容器里执行毫无意义

所以后期我们需要支持远程调用定期任务, 比如在一台机器上运行一个http服务, 使用token作为认证, 然后定期任务服务器通过http api方式调用这台机器来实现shell脚本的执行


第二个要解决的问题, 就是脚本的存储问题

最开始的想法是, 让用户上传一个脚本来执行, 但是后面发现, 有许多定期任务就是需要2个,3个文件, 甚至他需要一些配置文件来执行, 所以文件上传问题非常多,并且涉及到定期任务脚本有更新时, 用户还需要来重新上传脚本

所以这里想到了一个办法

就是大家都把定期任务的脚本存放到git上存储,这样不仅实现了脚本的版本控制, 也解决了脚本的存储问题

但是这样也会带来一个新的问题, 为了安全, 我们不能在git上明文存储任何密钥, 密码等敏感数据

所以我们需要在前端创建任务时, 用json的格式填一些敏感信息作为环境变量传入到容器, 然后在任务脚本里使用获取环境变量的方式获取这种敏感信息

{
  "ad_user": "xxxx",
  "ad_password": "xxxxx",
  "wechat_key": "xxxx"
}

并且我们需要在存储这些敏感数据时使用加密存储, 在前端展示给用户时也需要进行脱敏处理

当然这里会有一些小问题

  • 比如python, 用户需要在git仓库里导出自己的requirements, 然后我们构建容器时安装依赖
  • 比如go, 用户需要带上go.mod文件, 然后我们构建容器时安装依赖

第三个问题, 就是任务的日志存储

为了方便的查看任务输出, 我们可以在脚本中使用log库直接打印日志到标准输出, 然后我们的定期任务调度器直接读取容器的日志, 这样就可以拿到任务的日志信息, 不用再用文件来存储日志, 我们也可以直接从前端看到定期任务的日志

但是这样有一个小问题

  • 如果每一次执行任务都把任务的输出放到数据库中, 那么我们如何实现日志的过期与清理

所以后面想到了把任务日志存到redis里, 然后使用redis的ttl来实现日志的过期, 我们在数据库中只需要记录redis的key就可以读取到任务的日志输出了

超过存储期限的日志,在redis查不到, 我们可以给用户一个优雅的提示,显示日志过期


这两个核心问题解决以后, 就可以考虑我们需要解决的技术问题了

  • 前端需要有一个cron组件, 可以选择执行时间
  • 后端需要能解析cron表达式
  • 后端需要能支持重启程序后, 重新把任务加载到内存中
  • 需要学习怎么用Go去操作docker

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注