Skip to content

Commit

Permalink
Style guide, add scheduler/callback tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
nickelser committed Jun 29, 2016
1 parent d1b41fb commit 7af9d84
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 103 deletions.
7 changes: 5 additions & 2 deletions .rubocop.yml
Expand Up @@ -74,7 +74,7 @@ Style/SpaceInsideBrackets:
Style/AndOr:
Enabled: false

Style/TrailingComma:
Style/TrailingCommaInLiteral:
Enabled: true

Style/SpaceBeforeComma:
Expand All @@ -98,7 +98,7 @@ Style/SpaceAfterColon:
Style/SpaceAfterComma:
Enabled: true

Style/SpaceAfterControlKeyword:
Style/SpaceAroundKeyword:
Enabled: true

Style/SpaceAfterNot:
Expand Down Expand Up @@ -214,3 +214,6 @@ Metrics/ParameterLists:

Metrics/PerceivedComplexity:
Enabled: false

Style/Documentation:
Enabled: false
2 changes: 1 addition & 1 deletion Gemfile
@@ -1,4 +1,4 @@
source 'https://rubygems.org'
source "https://rubygems.org"

# Specify your gem's dependencies in zhong.gemspec
gemspec
4 changes: 4 additions & 0 deletions lib/zhong.rb
Expand Up @@ -31,6 +31,10 @@ def self.stop
scheduler.stop
end

def self.clear
scheduler.clear
end

def self.scheduler
@scheduler ||= Scheduler.new(logger: logger, redis: redis, tz: tz)
end
Expand Down
79 changes: 38 additions & 41 deletions lib/zhong/at.rb
Expand Up @@ -24,7 +24,7 @@ def self.parse(at, grace: 0.seconds)
parse_at(at, grace)
end
rescue ArgumentError
fail FailedToParse, at
raise FailedToParse, at
end

def self.deserialize(at)
Expand All @@ -37,7 +37,7 @@ def initialize(minute: nil, hour: nil, wday: nil, grace: 0.seconds)
@wday = wday
@grace = grace

fail ArgumentError unless valid?
raise ArgumentError unless valid?
end

def next_at(time = Time.now)
Expand All @@ -46,22 +46,19 @@ def next_at(time = Time.now)
grace_cutoff = time.change(sec: 0) - @grace

if at_time < grace_cutoff
if @wday.nil?
at_time += @hour.nil? ? 1.hour : 1.day
else
at_time += 1.week
end
at_time + if @wday.nil?
@hour.nil? ? 1.hour : 1.day
else
1.week
end
else
at_time
end
end

def to_s
str = "#{formatted_time(@hour)}:#{formatted_time(@minute)}"

if @wday
str += " on #{WDAYS.invert[@wday].capitalize}"
end
str += " on #{WDAYS.invert[@wday].capitalize}" if @wday

str
end
Expand All @@ -74,38 +71,25 @@ def serialize
MessagePack.pack(as_json)
end

protected

def formatted_time(t)
if t.nil?
"**"
def self.parse_serialized(at)
if at.is_a?(Array)
MultiAt.new(at.map { |a| parse_serialized(a) })
else
t.to_s.rjust(2, "0")
new(minute: at["m"], hour: at["h"], wday: at["w"], grace: at["g"])
end
end

def ==(o)
o.class == self.class && o.state == state
end

def state
[@minute, @hour, @wday]
end

private
private_class_method :parse_serialized

def self.parse_at(at, grace)
case at
when /\A([[:alpha:]]+)\s+(.*)\z/
wday = WDAYS[$1.downcase]

if wday
parsed_time = parse_at($2, grace)
parsed_time.wday = wday
parsed_time
else
fail FailedToParse, at
end
raise FailedToParse, at unless wday

parsed_time = parse_at($2, grace)
parsed_time.wday = wday
parsed_time
when /\A(\d{1,2}):(\d\d)\z/
new(minute: $2.to_i, hour: $1.to_i, grace: grace)
when /\A\*{1,2}:(\d\d)\z/
Expand All @@ -115,18 +99,31 @@ def self.parse_at(at, grace)
when /\A\*{1,2}:\*{1,2}\z/
new(grace: grace)
else
fail FailedToParse, at
raise FailedToParse, at
end
end
private_class_method :parse_at

def self.parse_serialized(at)
if at.is_a?(Array)
MultiAt.new(at.map { |a| parse_serialized(a) })
protected

def formatted_time(t)
if t.nil?
"**"
else
new(minute: at["m"], hour: at["h"], wday: at["w"], grace: at["g"])
t.to_s.rjust(2, "0")
end
end

def ==(other)
other.class == self.class && other.state == state
end

def state
[@minute, @hour, @wday]
end

private

def at_time_hour_minute_adjusted(time)
if @minute && @hour
time.change(hour: @hour, min: @minute)
Expand Down Expand Up @@ -157,8 +154,8 @@ def initialize(ats = [])
@ats = ats
end

def ==(o)
o.class == self.class && @ats == o.ats
def ==(other)
other.class == self.class && @ats == other.ats
end

def next_at(time = Time.now)
Expand Down
21 changes: 9 additions & 12 deletions lib/zhong/every.rb
Expand Up @@ -15,20 +15,17 @@ class FailedToParse < StandardError; end
def initialize(period)
@period = period

fail "`every` must be >= 1 second" unless valid?
raise "`every` must be >= 1 second" unless valid?
end

def to_s
EVERY_KEYWORDS.to_a.reverse.each do |friendly, period|
if @period % period == 0
rem = @period / period

if rem == 1
return "#{rem} #{friendly}"
else
return "#{rem} #{friendly}s"
end
end
next unless @period % period == 0

rem = @period / period

return "#{rem} #{friendly}" if rem == 1
return "#{rem} #{friendly}s"
end

"#{@period.to_i} second#{@period.to_i == 1 ? '' : 's'}"
Expand All @@ -49,11 +46,11 @@ def self.parse(every)
when String, Symbol
key = every.downcase.to_sym

fail FailedToParse, every unless EVERY_KEYWORDS.key?(key)
raise FailedToParse, every unless EVERY_KEYWORDS.key?(key)

new(EVERY_KEYWORDS[key])
else
fail FailedToParse, every
raise FailedToParse, every
end
end
end
Expand Down
8 changes: 6 additions & 2 deletions lib/zhong/job.rb
Expand Up @@ -11,7 +11,7 @@ def initialize(job_name, config = {}, &block)
@at = config[:at] ? At.parse(config[:at], grace: config.fetch(:grace, 15.minutes)) : nil
@every = config[:every] ? Every.parse(config[:every]) : nil

fail "must specific either `at` or `every` for job: #{self}" unless @at || @every
raise "must specific either `at` or `every` for job: #{self}" unless @at || @every

@block = block

Expand Down Expand Up @@ -39,6 +39,7 @@ def run(time = Time.now, error_handler = nil)

locked = false
errored = false
ran = false

begin
redis_lock.lock do
Expand All @@ -61,6 +62,7 @@ def run(time = Time.now, error_handler = nil)
if @block
begin
@block.call
ran = true
rescue => boom
logger.error "#{self} failed: #{boom}"
error_handler.call(boom, self) if error_handler
Expand All @@ -77,6 +79,8 @@ def run(time = Time.now, error_handler = nil)
@running = false

logger.info "unable to acquire exclusive run lock: #{self}" if !locked && !errored

ran
end

def running?
Expand All @@ -97,7 +101,7 @@ def enable
end

def disabled?
!!@redis.get(disabled_key)
!@redis.get(disabled_key).nil?
end

def to_s
Expand Down
24 changes: 19 additions & 5 deletions lib/zhong/scheduler.rb
Expand Up @@ -19,10 +19,18 @@ def initialize(config = {})
@tz = @config[:tz]
@category = nil
@error_handler = nil
@running = false
end

def clear
raise "unable to clear while running; run Zhong.stop first" if @running

@jobs = {}
@callbacks = {}
end

def category(name)
fail "cannot nest categories: #{name} would be nested in #{@category} (#{caller.first})" if @category
raise "cannot nest categories: #{name} would be nested in #{@category} (#{caller.first})" if @category

@category = name.to_s

Expand All @@ -32,7 +40,7 @@ def category(name)
end

def every(period, name, opts = {}, &block)
fail "must specify a period for #{name} (#{caller.first})" unless period
raise "must specify a period for #{name} (#{caller.first})" unless period

job = Job.new(name, opts.merge(@config).merge(every: period, category: @category), &block)

Expand All @@ -50,7 +58,7 @@ def error_handler(&block)
end

def on(event, &block)
fail "unknown callback #{event}" unless [:before_tick, :after_tick, :before_run, :after_run].include?(event.to_sym)
raise "unknown callback #{event}" unless [:before_tick, :after_tick, :before_run, :after_run].include?(event.to_sym)
(@callbacks[event.to_sym] ||= []) << block
end

Expand All @@ -61,7 +69,11 @@ def start

trap_signals

raise "already running" if @running

loop do
@running = true

if fire_callbacks(:before_tick)
now = redis_time

Expand All @@ -83,6 +95,8 @@ def start
break if @stop
end

@running = false

Thread.new { @logger.info "stopped" }.join
end

Expand Down Expand Up @@ -111,9 +125,9 @@ def jobs_to_run(time = redis_time)
def run_job(job, time = redis_time)
return unless fire_callbacks(:before_run, job, time)

job.run(time, error_handler)
ran = job.run(time, error_handler)

fire_callbacks(:after_run, job, time)
fire_callbacks(:after_run, job, time, ran)
end

def heartbeat(time)
Expand Down
2 changes: 1 addition & 1 deletion lib/zhong/version.rb
@@ -1,3 +1,3 @@
module Zhong
VERSION = "0.1.5"
VERSION = "0.1.5".freeze
end

0 comments on commit 7af9d84

Please sign in to comment.