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... 可能有些過期,可是個很好的開始。