class Zhong::Scheduler
Constants
- DEFAULT_CONFIG
- TRAPPED_SIGNALS
Attributes
jobs[R]
Public Class Methods
new(config = {})
click to toggle source
# File lib/zhong/scheduler.rb, line 14 def initialize(config = {}) @jobs = {} @callbacks = {} @config = DEFAULT_CONFIG.merge(config) @category = nil @error_handler = nil @running = false end
Public Instance Methods
category(name) { |self| ... }
click to toggle source
# File lib/zhong/scheduler.rb, line 32 def category(name) raise "cannot nest categories: #{name} would be nested in #{@category} (#{caller.first})" if @category @category = name.to_s yield(self) @category = nil end
clear()
click to toggle source
# File lib/zhong/scheduler.rb, line 24 def clear raise "unable to clear while running; run Zhong.stop first" if @running @jobs = {} @callbacks = {} @category = nil end
error_handler(&block)
click to toggle source
# File lib/zhong/scheduler.rb, line 52 def error_handler(&block) @error_handler = block if block_given? @error_handler end
every(period, name, opts = {}, &block)
click to toggle source
# File lib/zhong/scheduler.rb, line 42 def every(period, name, opts = {}, &block) raise "must specify a period for #{name} (#{caller.first})" unless period job = Job.new(name, opts.merge(@config).merge(every: period, category: @category), @callbacks, &block) raise "duplicate job #{job}" if jobs.key?(job.id) @jobs[job.id] = job end
find_by_name(job_name)
click to toggle source
# File lib/zhong/scheduler.rb, line 111 def find_by_name(job_name) @jobs[Digest::SHA256.hexdigest(job_name)] end
on(event, &block)
click to toggle source
# File lib/zhong/scheduler.rb, line 57 def on(event, &block) unless [:before_tick, :after_tick, :before_run, :after_run, :before_disable, :after_disable, :before_enable, :after_enable].include?(event.to_sym) raise "unknown callback #{event}" end (@callbacks[event.to_sym] ||= []) << block end
redis_time()
click to toggle source
# File lib/zhong/scheduler.rb, line 115 def redis_time s, ms = redis.time # returns [seconds since epoch, microseconds] now = Time.at(s + ms / (10**6)) tz ? now.in_time_zone(tz) : now end
start()
click to toggle source
# File lib/zhong/scheduler.rb, line 65 def start logger.info "starting at #{redis_time}" @stop = false trap_signals raise "already running" if @running loop do @running = true if fire_callbacks(:before_tick) now = redis_time jobs_to_run(now).each do |_, job| break if @stop run_job(job, now) end break if @stop fire_callbacks(:after_tick) heartbeat(now) break if @stop else logger.info "skipping tick due to a `:before_tick` callback" end sleep_until_next_second break if @stop end @running = false Thread.new { logger.info "stopped" }.join end
stop()
click to toggle source
# File lib/zhong/scheduler.rb, line 106 def stop Thread.new { logger.error "stopping" } if @running # thread necessary due to trap context @stop = true end
Private Instance Methods
fire_callbacks(event, *args)
click to toggle source
# File lib/zhong/scheduler.rb, line 126 def fire_callbacks(event, *args) @callbacks[event].to_a.map do |callback| callback.call(*args) end.compact.all? # do not skip on nils end
heartbeat(time)
click to toggle source
# File lib/zhong/scheduler.rb, line 147 def heartbeat(time) redis.hset(heartbeat_key, heartbeat_field, time.to_i) end
heartbeat_field()
click to toggle source
# File lib/zhong/scheduler.rb, line 151 def heartbeat_field @heartbeat_field ||= "#{`hostname`.strip}##{Process.pid}" end
jobs_to_run(time = redis_time)
click to toggle source
# File lib/zhong/scheduler.rb, line 132 def jobs_to_run(time = redis_time) jobs.select { |_, job| job.run?(time) } end
run_job(job, time = redis_time)
click to toggle source
# File lib/zhong/scheduler.rb, line 136 def run_job(job, time = redis_time) unless fire_callbacks(:before_run, job, time) logger.info "skipping #{job} due to a `:before_run` callback" return end ran = job.run(time, error_handler) fire_callbacks(:after_run, job, time, ran) end
sleep_until_next_second()
click to toggle source
# File lib/zhong/scheduler.rb, line 161 def sleep_until_next_second GC.start sleep(1.0 - Time.now.subsec + 0.0001) end
trap_signals()
click to toggle source
# File lib/zhong/scheduler.rb, line 155 def trap_signals TRAPPED_SIGNALS.each do |sig| Signal.trap(sig) { stop } end end