本文章目的是带您了解如何在 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 定期任务步骤(手动,假定开发环境):
- 在 config/schedule.rb 中,编辑定义 cron 任务,保存
- 使用
whenever --update-crontab --set environment=development
写入和更新 cron 任务 - 使用
crontab -l
查看 cron 任务,检查是否成功写入和更新
编辑 Cron 任务
Whenever Gem 官方说明(
文献[1]
)里有正常情况下的 schedule.rb 文件的编辑例子。但如果您使用了 Ruby 管理工具 ( rbenv 或 rvm ),明明在控制台中 rails
,bundle
命令都是正常可用的,但在 Cron 任务中可能就会出现异常报错。因此,我们还需要一些额外的配置来处理这种情况。打开 config/schedule.rb,我们可以修改配置和编辑 Cron 任务:
本文项目采用 rbenv 来管理 Ruby,因此仅举例解决 rbenv 带来的问题。其他 Ruby 管理工具类同。
如果您的项目在当前环境中一切运行正常,但 Cron 任务在运行时遇见如下任一错误:
- bundle: command not found
- bundler not found
- GemNotFoundException
- Missing 'secret_key_base'
# 本地
# 打开 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 定期任务是最新的。恭喜!!!
参考文献
- Javan / Whenever. GITHUB. https://github.com/javan/whenever
- Using rbenv in cron jobs. BENSCHEIRMAN. https://benscheirman.com/2013/12/using-rbenv-in-cron-jobs.html