diff --git a/bin/whenever_server b/bin/whenever_server new file mode 100755 index 00000000..8bd72528 --- /dev/null +++ b/bin/whenever_server @@ -0,0 +1,38 @@ +#!/usr/bin/env ruby + +require 'whenever' +require 'redis' + +options = {} + +OptionParser.new do |opts| + opts.banner = "Usage: whenever [options]" + + opts.on('-f', '--load-file [schedule file]', 'Default: config/schedule.rb') do |file| + options[:file] = file if file + end +end.parse! + +job_list = Whenever::JobList.new(file: options[:file] || 'config/schedule.rb') + +puts(false) unless job_list.redis_options + +redis = Redis.new(job_list.redis_options) + +# redis key +lock = :whenever_server + +# get the server that has the lock +whenever_server = redis.get lock + +# if there is no server with the lock, give the lock to the current server +if whenever_server.nil? + redis.multi do + redis.setnx lock, Socket.gethostname + # expire hourly + redis.expire lock, 3600 + end +end + +# return true/false if the current server should be running the task or not +puts redis.get(lock) == Socket.gethostname \ No newline at end of file diff --git a/lib/whenever/job_list.rb b/lib/whenever/job_list.rb index 76b358fc..b7500fab 100644 --- a/lib/whenever/job_list.rb +++ b/lib/whenever/job_list.rb @@ -21,6 +21,8 @@ def initialize(options) File.read(options[:file]) end + @options = options + instance_eval(setup, setup_file) instance_eval(schedule, options[:file] || '') end @@ -48,6 +50,9 @@ def job_type(name, template) singleton_class_shim.class_eval do define_method(name) do |task, *args| options = { :task => task, :template => template } + + options[:template] = "cd :path && if whenever_server #{ "-f #{@options[:file]}" if @options[:file] && @options[:file] != 'config/schedule.rb'} >> /dev/null ; then #{options[:template]} ; fi" if @redis_options + options.merge!(args[0]) if args[0].is_a? Hash # :cron_log was an old option for output redirection, it remains for backwards compatibility diff --git a/lib/whenever/setup.rb b/lib/whenever/setup.rb index e2a02c41..b8009827 100644 --- a/lib/whenever/setup.rb +++ b/lib/whenever/setup.rb @@ -9,6 +9,9 @@ # http://blog.scoutapp.com/articles/2010/09/07/rvm-and-cron-in-production set :job_template, "/bin/bash -l -c ':job'" +# Multiple servers support +set :redis_options, nil + set :runner_command, case when Whenever.bin_rails? "bin/rails runner" diff --git a/test/functional/output_whenever_server_test.rb b/test/functional/output_whenever_server_test.rb new file mode 100644 index 00000000..3586511a --- /dev/null +++ b/test/functional/output_whenever_server_test.rb @@ -0,0 +1,16 @@ +require 'test_helper' + +class OutputWheneverServer < Whenever::TestCase + test 'command when the redis_options is set' do + output = Whenever.cron \ + <<-file + set :redis_options, :url => 'redis://localhost:6379/1' + every :hour do + set :path, "/tmp" + command "blahblah" + end + file + + assert_match "0 * * * * /bin/bash -l -c 'cd /tmp && if whenever_server >> /dev/null ; then blahblah ; fi'", output + end +end \ No newline at end of file diff --git a/whenever.gemspec b/whenever.gemspec index 970566f3..6c7d7bce 100644 --- a/whenever.gemspec +++ b/whenever.gemspec @@ -18,7 +18,7 @@ Gem::Specification.new do |s| s.require_paths = ["lib"] s.add_dependency "chronic", ">= 0.6.3" - + s.add_dependency "redis" s.add_development_dependency "mocha", ">= 0.9.5" s.add_development_dependency "rake" s.add_development_dependency "minitest"