class Librato::Rack::Worker

Runs a given piece of code periodically, ensuring that it will be run again at the proper interval regardless of how long execution takes.

Attributes

timer[R]

Public Class Methods

new(options={}) click to toggle source

available options:

* timer - type of timer to use, valid options are
          :sleep (default), :eventmachine, or :synchrony
* sync  - try to synchronize timer executions to whole
          minutes or subdivisions thereof
# File lib/librato/rack/worker.rb, line 15
def initialize(options={})
  @interrupt = false
  @timer = (options[:timer] || :sleep).to_sym
  @sync = options[:sync] || false
end

Public Instance Methods

run_periodically(period, &block) click to toggle source

run the given block every <period> seconds, looping infinitely unless @interrupt becomes true.

# File lib/librato/rack/worker.rb, line 24
def run_periodically(period, &block)
  @proc = block # store

  if [:eventmachine, :synchrony].include?(timer)
    compensated_repeat(period) # threading is already handled
  else
    @thread = Thread.new { compensated_repeat(period) }
  end
end
start_time(period) click to toggle source

Give some structure to worker start times so when possible they will be in sync.

# File lib/librato/rack/worker.rb, line 37
def start_time(period)
  if @sync
    earliest = Time.now + period
    # already on a whole minute
    return earliest if earliest.sec == 0
    if period > 30
      # bump to whole minute
      earliest + (60-earliest.sec)
    else
      # ensure sync to whole minute if minute is evenly divisible
      earliest + (period-(earliest.sec%period))
    end
  else
    if period > 30
      # ensure some wobble in start times,
      # trade a slightly irregular first period for a more even
      # distribution for network requests between processes
      start = Time.now
      start + (60-start.sec) + rand(60)
    else
      Time.now + period
    end
  end
end
stop!() click to toggle source

stop worker loop at the beginning of the next round of execution

# File lib/librato/rack/worker.rb, line 64
def stop!
  @interrupt = true
end

Private Instance Methods

compensated_repeat(period, first_run = nil) click to toggle source

run continuous loop executing every <period>, will start at <first_run> if set otherwise will auto-determine appropriate time for first run

# File lib/librato/rack/worker.rb, line 73
def compensated_repeat(period, first_run = nil)
  next_run = first_run || start_time(period)
  until @interrupt do
    now = Time.now
    if now >= next_run
      @proc.call

      while next_run <= now
        next_run += period # schedule future run
      end
    end

    interval = next_run - now
    case timer
    when :eventmachine
      EM.add_timer(interval) { compensated_repeat(period, next_run) }
      break
    when :synchrony
      EM::Synchrony.sleep(interval)
    else
      sleep(next_run - now)
    end
  end
end