Class: Yuuki::PeriodicCaller

Inherits:
Caller
  • Object
show all
Defined in:
lib/yuuki/periodic_caller.rb,
sig/yuuki/periodic_caller.rbs

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Caller

#add, #alive?, #join, #methods, require_dir, #run_internal, #run_method_internal, #run_select

Constructor Details

#initialize(*instances, use_yoshinon: true) ⇒ PeriodicCaller

Returns a new instance of PeriodicCaller.

Parameters:

  • instances (Runner, Class)
  • use_yoshinon: (Boolean) (defaults to: true)


11
12
13
14
# File 'lib/yuuki/periodic_caller.rb', line 11

def initialize(*instances, use_yoshinon: true)
  super
  @first_run = true
end

Instance Attribute Details

#current_timeFloat? (readonly)

epoch seconds of the current iteration; nil before #run is called

Returns:

  • (Float, nil)


9
10
11
# File 'sig/yuuki/periodic_caller.rbs', line 9

def current_time
  @current_time
end

#first_runBoolean (readonly)

true until the first iteration of #run has finished

Returns:

  • (Boolean)


6
7
8
# File 'sig/yuuki/periodic_caller.rbs', line 6

def first_run
  @first_run
end

Instance Method Details

#on_error {|arg0| ... } ⇒ void

This method returns an undefined value.

Yields:

Yield Parameters:

  • arg0 (StandardError)

Yield Returns:

  • (Object)


16
17
18
# File 'lib/yuuki/periodic_caller.rb', line 16

def on_error(&block)
  @on_error = block
end

#run(gmtoff = Time.now.gmtoff, **args, &block) ⇒ void

This method returns an undefined value.

loops forever; only returns by raising (when no on_error callback is set)

Parameters:

  • gmtoff (Integer) (defaults to: Time.now.gmtoff)
  • args (Object)


16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'sig/yuuki/periodic_caller.rbs', line 16

def run(gmtoff = Time.now.gmtoff, **args, &block)
  last_time = nil
  loop do
    @current_time = Time.now.to_f
    begin
      selector = proc do |_method, meta|
        next true if @first_run && meta[:first_run]
        next false unless meta[:periodic]
        next false unless last_time

        # gmtoff shifts epoch seconds into local time so that intervals
        # align with local clock boundaries (e.g. 86400 fires at local midnight).
        # Fires when a multiple of the interval lies in (last_time, current_time].
        c = @current_time + gmtoff
        l = last_time + gmtoff
        (l.div(meta[:periodic]) + 1) * meta[:periodic] <= c
      end
      run_select(selector, **args, &block)
    rescue StandardError
      @on_error ? @on_error[$!] : raise
    end
    @first_run = false

    last_time = @current_time
    # wake at the next wall-clock second; the boundary check above makes
    # ticks drift-free, but intervals below 1 second cannot be honored
    sleep_duration = (@current_time + 1).floor - Time.now.to_f
    sleep(sleep_duration) if sleep_duration > 0
  end
end