设定 Cron 定期任务

Ubuntu 22.04 + Rbenv + Whenever + Capistrano

249 次阅读

本文章目的是带您了解如何在 rbenv 环境内,设定 cron 定期任务。我们将用 Whenever Gem 来完成,它提供了清晰简单的语法,方便我们编辑和更新 cron 定期任务。最后结合 Capistrano,我们将实现自动化更新、部署 cron 定期任务。希望对您有所帮助。

安装 Whenever

Whenever 是一个 Ruby gem,它为编写和部署 cron 定期任务提供了清晰的语法。有关它的详细资料,请查看 文献[1] 。现在,我们来安装它:

# 本地
# 打开 Gemfile,添加 Whenever Gem
gem 'whenever', require: false

# 保存文件后,安装和初始化 Whenever
bundle install
bundle exec wheneverize .

如果不出意外,Whenever 将会创建一个新 config/schedule.rb 文件在您的项目中,该文件就是今后编辑 cron 定期任务的地方。除此之外,我们还需要了解 Whenever 的相关命令操作:

# 本地
# 查看 Whenever 命令列表
whenever --help

我们重点关注 whenever --update-crontab(用于写入和更新 cron 定期任务)whenever --clear-crontab(用于清空 cron 定期任务) 这两个常用命令。还有 --set environment=YOUR_ENV 参数,用来指定所属环境。最后,crontab -l 命令可以查看已安装的 cron 定期任务。

完整的设定 Cron 定期任务步骤(手动,假定开发环境):

  1. 在 config/schedule.rb 中,编辑定义 cron 任务,保存
  2. 使用 whenever --update-crontab --set environment=development 写入和更新 cron 任务
  3. 使用 crontab -l 查看 cron 任务,检查是否成功写入和更新

编辑 Cron 任务

Whenever Gem 官方说明( 文献[1] )里有正常情况下的 schedule.rb 文件的编辑例子。但如果您使用了 Ruby 管理工具 ( rbenv 或 rvm ),明明在控制台中 railsbundle 命令都是正常可用的,但在 Cron 任务中可能就会出现异常报错。因此,我们还需要一些额外的配置来处理这种情况。打开 config/schedule.rb,我们可以修改配置和编辑 Cron 任务:

本文项目采用 rbenv 来管理 Ruby,因此仅举例解决 rbenv 带来的问题。其他 Ruby 管理工具类同。

如果您的项目在当前环境中一切运行正常,但 Cron 任务在运行时遇见如下任一错误:

  • bundle: command not found
  • bundler not found
  • GemNotFoundException
  • Missing 'secret_key_base'
那么,很有可能是 rbenv 路径和初始化导致的错误。因此,我们需要将 rbenv 的 shims 文件夹添加到我们的路径中,并在运行 Cron 任务命令之前初始化 rbenv,以确保它们与正确初始化的 rbenv 一起运行。

# 本地
# 打开 config/schedule.rb 文件
# output 参数是用来指定 Cron 任务内容输出(如果有的话)的文件路径
# 如果您希望将内容保存在项目的 log 文件夹内的 schedule.log 文件中的话,那么设置如下:
set :output, "log/schedule.log"

# Whenever 默认的任务命令类型如下:
#
# job_type :command, ":task :output"
# job_type :rake, "cd :path && :environment_variable=:environment bundle exec rake :task --silent :output"
# job_type :runner, "cd :path && bin/rails runner -e :environment ':task' :output"
# job_type :script, "cd :path && :environment_variable=:environment bundle exec script/:task :output"
#
# 为了修复 rbenv 路径和初始化导致的错误,我们需要定义新的 Whenever 任务命令类型
#
# 在原有的任务命令执行之前,添加
# export PATH=~/.rbenv/shims:~/.rbenv/bin:/usr/bin:$PATH; 命令,将 rbenv 的 shims 文件夹添加到路径中;
# eval "$(rbenv init -)"; 命令,初始化 rbenv。
#
# 在这里,我们仅定义新的 rake 和 runner 命令,如下:
job_type :rbenv_rake, %Q{export PATH=~/.rbenv/shims:~/.rbenv/bin:/usr/bin:$PATH; eval "$(rbenv init -)"; cd :path && :environment_variable=:environment bundle exec rake :task --silent :output}
job_type :rbenv_runner, %Q{export PATH=~/.rbenv/shims:~/.rbenv/bin:/usr/bin:$PATH; eval "$(rbenv init -)"; cd :path && bin/rails runner -e :environment ':task' :output}

# @environment 参数可以获取当前环境,方便我们编辑设定不同环境下的不同 Cron 任务
case @environment
when "development"

every 1.minute do

rbenv_runner "MyModel.some_method"

end

when "production"

every 1.minute do

rbenv_runner "MyModel.some_method"

end

end

结合 Capistrano

前面我们简要介绍过手动完整设定 Cron 定期任务的步骤。现在我们结合 Capistrano 来实现自动化设定、更新、部署 Cron 定期任务。

我们先来编辑 Capfile 文件,添加以下内容:

# 本地
# 打开修改 Capfile 文件
# 添加 Whenever 相关任务
require "whenever/capistrano"

然后,我们来编辑 config/deploy.rb 文件,添加以下内容:

# 本地
# 打开修改 config/deploy.rb 文件
# 为避免不同环境中的 Cron 任务相互覆盖,我们在不同环境下命名不同的 crontab 条目
set :whenever_identifier, ->{ "#{fetch(:application)}_#{fetch(:whenever_environment)}" }

至此,我们完成了所有的配置和设定,使用 cap production deploy(修改 deploy 成您的远程用户名) 命令即可完成生产环境上的一键部署。Capistrano 会在每次部署时自动执行 whenever --update-crontab --set environment=production(假定在生产环境) 命令,以确保您的 Cron 定期任务是最新的。恭喜!!!

参考文献

  1. Javan / Whenever. GITHUB. https://github.com/javan/whenever
  2. Using rbenv in cron jobs. BENSCHEIRMAN. https://benscheirman.com/2013/12/using-rbenv-in-cron-jobs.html