module CronR::Utils

Public Class Methods

every(secs,debug=false,&block) click to toggle source

Wake up every 'secs' number of seconds and call block.

We measure 'secs' after the function call. So it is not aligned to anything.

# File lib/CronR/utils.rb, line 92
def self.every secs,debug=false,&block
  Thread.new {
    loop {
      result = block.call
      if result==true then
        break
      end
      #p "[every] sleeping #{secs}" if debug
      sleep secs
    }
  }
end
every_minute(debug=false,&block) click to toggle source

Wake up every minute and call &block.

Returns the thread that does the waking up. If &block returns true, then stop.

# File lib/CronR/utils.rb, line 66
def self.every_minute debug=false,&block
  mil = 1000000
  secs = 60.0
  Thread.new {
    now = Time.now
    wait = secs-now.sec-now.usec.to_f/mil
    #p "[every_minute] sleeping #{wait}" if debug
    sleep wait
    loop {
      result = block.call
      if result==true then
        break
      end
      now = Time.now
      wait = secs-now.sec-now.usec.to_f/mil
      #p "[every_minute] sleeping #{wait}" if debug
      sleep(wait)
    }
  }
end
make_waitsecs_epoch(secs) click to toggle source

Make a function that returns time to wait till the next secs-th second of the unix epoch.

MOTIVATION

make_waitsecs_time breaks up the minute starting from the 0th second and the maximum cycle is therefore 60. Here we can apply '% secs' for arbitrary value 'secs' up to the current epoch, although such large values would be of little use.

# File lib/CronR/utils.rb, line 153
def self.make_waitsecs_epoch secs
  if secs < 1 then
    raise "secs must be > 1"
  end
  mil = 1000000
  lambda{|time=nil|
    time = Time.now if time.nil?
    sec = time.to_i # unix timestamp
    usec = time.tv_usec # fraction unix component
    frac = usec.to_f/mil
    remainder = secs - ((sec+1) % secs)
    remainder -= frac
    if remainder < 0
      # TODO if frac is almost zero, return zero here?
      remainder + secs
    else
      remainder
    end
  }
end
make_waitsecs_time(secs) click to toggle source

Make a function that returns time to wait till the next secs-th second of each minute.

MOTIVATION

every_minute wakes up every minute on the minute. Can we wake up every several seconds, on the second? Can we break a minute up into intervals starting from the 0th second in the minute?

l = make_waitsecs_time(3)
wait = l.call
sleep(wait)
# So, right *now*:
# Time.now.sec ~ s where (0..57).step(3).to_a.include?(s)
# File lib/CronR/utils.rb, line 122
def self.make_waitsecs_time secs
  if secs < 1 || secs > 60 then
    raise "secs must be 1-60"
  end
  mil = 1000000
  lambda{|time=nil|
    time = Time.now if time.nil?
    sec = time.sec
    usec = time.usec
    frac = usec.to_f/mil
    remainder = secs - ((sec+1) % secs)
    remainder -= frac
    if remainder < 0
      # TODO if frac is almost zero, return zero here?
      remainder + secs
    else
      remainder
    end
  }
end
parse_param(str) click to toggle source

Parse a single cron parameter into a format that CronR uses.

Currently not used directly by CronR. But may be handy for translating cron parameters.

'*' => true '1' => 1 '1-3' => [1,2,3] Other forms which translate to arrays: '*/3' '1-5/2' '2,4,8' '2-4,6-8'

In the case of */3 we do: (1..59).step(3).to_a which will hopefully cover all cases.

# File lib/CronR/utils.rb, line 25
def self.parse_param str
  parts = str.split(',')
  if parts.empty? || parts.detect{|i| i.empty? } then
    raise "Not enough information to process parameter: '#{str}'."
  end
  parts.map { |p|
    n, step = p.split('/')
    raise "No number before slash: '#{str}'" if n.empty?
    a, b = n.split('-')
    raise "No number before hyphen: '#{str}'" if a.empty?
    a = a.strip
    raise "Not a number or asterisk: '#{a}'" unless /^\d+$|^\*$/ === a
    if b then
      a, b = a.to_i, b.to_i
      if step then
        (a..b).step(step.to_i).to_a
      else
        (a..b).to_a
      end
    else
      case a
      when '*'
        if step then
          # Bit cheap, basically we'll cover ourselves for all
          # component types by going up to 59
          (0..59).step(step.to_i).to_a
        else
          return true  # ick, exit def
        end
      else
        [a.to_i]
      end
    end
  }.flatten
end