Whenever 是一个 Ruby gem,它提供了清晰的语法用于编写和部署 cron jobs。本文翻译自它的 Github:https://github.com/javan/when...html
$ gem install whenever
或者写到 Gemfile,配合Bundle:java
gem 'whenever', require: false
$ cd /apps/my-great-project $ bundle exec wheneverize .
为你建立初始化配置文件 config/schedule.rb
(只要你的目录下有 config 文件夹)。git
whenever
命令只是将 schedule.rb
文件的内容输出为 cron 语法结构,并不会读取和写入你的 crontab 文件。github
$ cd /apps/my-great-project $ bundle exec whenever
若是要将这些任务写入到 crontab 文件中去,带参数执行命令:api
$ whenever --update-crontab
其余经常使用命令:ruby
$ whenever --user app # set a user as which to install the crontab $ whenever --load-file config/my_schedule.rb # set the schedule file $ whenever --crontab-command 'sudo crontab' # override the crontab command
提示:若是你运行 whenever --update-crontab 没有附带 --user 选项,所生成的 cron 将只能被当前用户执行。这意味着若是你所执行的任务须要其余用户的权限,将失败。
可使用 crontab -l
列出当前当前系统的任务列表。bash
运行 whenever --help
,输出一些用于调度的选项、调度变量以及其余内容。服务器
every 3.hours do # 1.minute 1.day 1.week 1.month 1.year is also supported # the following tasks are run in parallel (not in sequence) runner "MyModel.some_process" rake "my:rake:task" command "/usr/bin/my_great_command" end every 1.day, at: '4:30 am' do runner "MyModel.task_to_run_at_four_thirty_in_the_morning" end every 1.day, at: ['4:30 am', '6:00 pm'] do runner "Mymodel.task_to_run_in_two_times_every_day" end every :hour do # Many shortcuts available: :hour, :day, :month, :year, :reboot runner "SomeModel.ladeeda" end every :sunday, at: '12pm' do # Use any day of the week or :weekend, :weekday runner "Task.do_something_great" end every '0 0 27-31 * *' do command "echo 'you can use raw cron syntax too'" end # run this task only on servers with the :app role in Capistrano # see Capistrano roles section below every :day, at: '12:20am', roles: [:app] do rake "app_server:task" end
Whenever 内置三种类型的工做:command,runner 以及 rake。你能够经过定义job_type
,来定义你本身的工做类型。app
举个例子:ide
job_type :awesome, '/usr/local/bin/awesome :task :fun_level' every 2.hours do awesome "party", fun_level: "extreme" end
这段例子的意思是,每两个小时,执行一次 /usr/local/bin/awesome party extreme
。:task
老是做为第一个参数,额外的参数被替换其余传递的内容,或者使用 set
定义的变量。
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"
Rails 3 以前的应用程序,和不使用 Bundler 的应用程序,将分别从新定义 rake 和runner,以使其正常运行。
若是 :path
没有设置,使用当前whenever
执行的目录。:environment_variable
变量默认使用 RAILS_ENV
。:environment
默认设置为production
。:outpuot
用于配置你的输出重定向,能够在(这里)[http://github.com/javan/whene...],了解到如何配置。
全部的工做默认经过 bash -l -c 'command'
来执行。这会使你的 cron job 加载整个环境变量,而不是 cron 执行的有限环境。这让你的 rvm 工做的更好。了解更多:http://github.com/javan/whene...
你能够经过定义 :job_template
来改变这一默认行为。
set :job_template, "bash -l -c ':job'"
设置 :job_setemplate
为空,来恢复标准行为:
set :job_template, nil
Whenever 使用 (Chronic)[https://github.com/mojombo/ch...] gem,来解析指定的日期和时间。
若是默认的 Chronic 配置不适合你,你能够自定义。
举一个例子,使用24小时制,来替换默认的12小时制:
set :chronic_options, hours24: true # By default this would run the job every day at 3am every 1.day, at: '3:00' do runner "MyModel.nightly_archive_job" end
能够在这里找到配置选项:
https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb
经过 MAILTO
环境变量,自定义 email 接收对象
工做的结果,能够输出到电子邮件地址,经过 MAILTO
环境变量来配置。
多种方式能够配置邮件接受地址:
全局配置例子:
env 'MAILTO', 'output_of_cron@example.com' every 3.hours do command "/usr/bin/my_great_command" end
只在一个代码块中生效的例子:
every 3.hours, mailto: 'my_super_command@example.com' do command "/usr/bin/my_super_command" end
只在一个工做中生效的例子:
every 3.hours do command "/usr/bin/my_super_command", mailto: 'my_super_command_output@example.com' end
使用内置的 Capistrano recipe,便可完成简单的 crontab 部署时更新。 Capistrano V3 的使用,将在下一节介绍。
打开 "config/deploy.rb" 文件:
require "whenever/capistrano"
在这里https://github.com/javan/whenever/blob/master/lib/whenever/capistrano/v2/recipes.rb 你能够找到 recipe 可使用的配置项。好比你想使用 bundler:
set :whenever_command, "bundle exec whenever" require "whenever/capistrano"
若是你想在不一样的环境中使用(如 staging,production),你能够这么用:
set :whenever_environment, defer { stage } require "whenever/capistrano"
capistrano 变量 :stage 保存着当前环境的名称。这将在 schedule.rb 文件中提供正确的 :environment。
若是你的两个环境,在同一台服务器上,你须要为他们提供命名空间,不然将在部署时相互覆盖:
set :whenever_environment, defer { stage } set :whenever_identifier, defer { "#{application}_#{stage}" } require "whenever/capistrano"
若是你要在别的路径开启调度,你须要这样配置:
set :whenever_load_file, defer { "#{release_path}/somewhere/else/schedule.rb" } require "whenever/capistrano"
打开你的 "Capfile" 文件:
require "whenever/capistrano"
查看文件底部的 load:default task 以了解能够配置的选项。举个例子,crontab 的 application 或 stage 命名空间条目的行为,在 "config/deploy.rb" 文件中配置。
set :whenever_identifier, ->{ "#{fetch(:application)}_#{fetch(:stage)}" }
集成 Capistrano,默认指望 :application
变量被设置,以便在 crontab 中肯定做业范围。
关于权限,首先要知道的是它是彻底可选的,以及向后兼容。若是你不须要 Crontabs 部署不一样的工做,在不一样的服务器上,你能够中止阅读,并放心的跳过这块的内容,一切都工做的很好。
当你在 schedule.rb 文件中定义工做的时候,默认它会被分发到全部在 whenever_roles 列表中的服务器。(该列表默认为 [:db]
):
very :day, at: '12:20am' do rake 'foo:bar' end
若是咱们在 deploy.rb 中,设置 whenever_roles 为 [:db, :app],以及 schedule.rb 中加入工做:
every :day, at: '1:37pm', roles: [:app] do rake 'app:task' # will only be added to crontabs of :app servers end every :hour, roles: [:db] do rake 'db:task' # will only be added to crontabs of :db servers end every :day, at: '12:02am' do command "run_this_everywhere" # will be deployed to :db and :app servers end
简单的规则:
若是你的产品生产环境,使用 RVM(Ruby Version Manager),你将会遇到一个致使你的 cron job 挂起的陷阱。这与 whenever 并没有直接关联,调试起来很麻烦。你的 .rvmrc 文件必须被可信,不然 cron jobs 将挂起等待该文件受信任。一个解决办法是,将这一行添加到 ~/.rvmrc 中,来禁止这个提示。
rvm_trust_rvmrcs_flag=1
这表示 rvm 将信任全部的 rvmrc 文件。
Heroku 不支持 cron,做为替代,提供了Heroku Scheduler。若是你要部署到 Herku,你要使用它,而不是 Whenever。
whenever-test 是一个 Whenever 的扩展,用于测试 Whenever schedule。
Whenever 的诞生,是为了使用 Inkling(http://inklingmarkets.com/)。能够在这里进行了解:http://blog.inklingmarkets.co...。
谢谢全部贡献者,是他们让 Whenever 变得更好:http://github.com/javan/whene...
通常的讨论和问题,请访问 google group:http://groups.google.com/group/whenever-gem
若是你遇到大 bug 或者问题,可使用 github 的 issue:http://github.com/javan/whene...
Ryan Bates 建立了一份很好的关于 Whenever 的 Railscast:http://railscasts.com/episode... 可能有些过期,可是个很好的开始。