Module: CronR::Utils

Defined in:
lib/CronR/utils.rb

Class Method Summary collapse

Class Method Details

.every(secs, debug = false, &block) ⇒ Object

Wake up every ‘secs’ number of seconds and call block.

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



92
93
94
95
96
97
98
99
100
101
102
103
# 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) ⇒ Object

Wake up every minute and call &block.

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



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# 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) ⇒ Object

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.



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# 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) ⇒ Object

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)


122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# 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) ⇒ Object

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.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 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