Skip to content

Instantly share code, notes, and snippets.

@cheald
Created October 24, 2012 00:58
Show Gist options
  • Save cheald/3943062 to your computer and use it in GitHub Desktop.
Save cheald/3943062 to your computer and use it in GitHub Desktop.
require 'rufus/scheduler'
class CronManager
def self.schedule(redis, &block)
@singleton ||= new(redis, &block)
end
def every(timing, options = {}, &block)
# In order to make sure that jobs are executed at the same time regardless of who runs them
# we quantitize the start time to the next-nearest time slice. This more closely emulates
# cron-style behavior.
#
# This does assume that your system dates are in sync.
seconds = Rufus.parse_duration_string(timing)
now = Time.now.to_i
start_at = Time.at( now + (seconds - (now % seconds)) )
options = options.merge(:first_at => start_at)
schedule :every, timing, options, &block
end
def cron(timing, options = {}, &block)
schedule :cron, timing, options, &block
end
private
def schedule(method, timing, options, &block)
name = options.delete :name
key = "cron:%s-%s" % [timing, name || Digest::SHA1.hexdigest(block.to_ruby)]
@scheduler.send method, timing, options do
# If we can acquire a lock...
if @redis.setnx key
# ...set the lock to expire in 95% of the duration's time, to account for system time drift
@redis.expire key, (seconds * 0.95).floor
# ...and then run the job
block.call
end
end
end
def initialize(redis, &block)
@redis = redis
@scheduler = Rufus::Scheduler.start_new
instance_eval &block
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment