Class: Iyyov::Task
Overview
A task to be scheduled and run.
Instance Attribute Summary collapse
-
#fixed_days ⇒ Object
Array or range for days of week in which fixed_times apply.
-
#fixed_times ⇒ Object
One or more fixed time values in 24hour format, local timezone, i.e: [ “11:30”, “23:30” ].
-
#log ⇒ Object
readonly
SLF4J logger.
-
#mode ⇒ Object
Execution mode.
-
#name ⇒ Object
Name the task for log reporting.
-
#next_time ⇒ Object
readonly
Once schedule succeeds, the absolute next time to execute.
-
#period ⇒ Object
Regular interval between subsequent executions in seconds.
Instance Method Summary collapse
- #filter(rc) ⇒ Object
-
#initialize(opts = {}, &block) ⇒ Task
constructor
New task given options matching accessors and block containing work.
- #next_fixed_time(now) ⇒ Object
- #next_time_to_s ⇒ Object
-
#run ⇒ Object
Execute the task, after which the task will be scheduled again in period time or for the next of fixed_times, unless :stop is returned.
- #run_direct ⇒ Object
- #run_thread ⇒ Object
-
#schedule(now) ⇒ Object
Determine next_time from now based on period or fixed_times.
- #test_async_return_code ⇒ Object
- #time_on_date(d, t) ⇒ Object
Constructor Details
#initialize(opts = {}, &block) ⇒ Task
New task given options matching accessors and block containing work.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/iyyov/task.rb', line 63 def initialize( opts = {}, &block ) @name = nil @next_time = nil @period = nil @fixed_times = nil @fixed_days = (0..6) #all opts.each { |k,v| send( k.to_s + '=', v ) } @block = block unless period || fixed_times raise( SetupError, "Task #{ opts.inspect } needs one of period or fixed_times" ) end @log = SLF4J[ [ SLF4J[ self.class ].name, name ].compact.join( '.' ) ] @lock = ( Mutex.new if mode == :async ) @async_rc = nil @log.info { "Task created : #{ opts.inspect }" } end |
Instance Attribute Details
#fixed_days ⇒ Object
Array or range for days of week in which fixed_times apply. Days are 0 (Sunday) .. 6 (Saturday). Example: M-F == (1..5)
~include?( day_of_week ) (default: (0..6))
42 43 44 |
# File 'lib/iyyov/task.rb', line 42 def fixed_days @fixed_days end |
#fixed_times ⇒ Object
One or more fixed time values in 24hour format, local timezone, i.e: [ “11:30”, “23:30” ]
Array(String) (default: nil, use period)
36 37 38 |
# File 'lib/iyyov/task.rb', line 36 def fixed_times @fixed_times end |
#log ⇒ Object (readonly)
SLF4J logger
59 60 61 |
# File 'lib/iyyov/task.rb', line 59 def log @log end |
#mode ⇒ Object
Execution mode. If :async, run in separate thread, but only allow one thread for this task to run at any time.
Symbol :sync|:async (default: :sync)
53 54 55 |
# File 'lib/iyyov/task.rb', line 53 def mode @mode end |
#name ⇒ Object
Name the task for log reporting.
String (default: nil)
47 48 49 |
# File 'lib/iyyov/task.rb', line 47 def name @name end |
#next_time ⇒ Object (readonly)
Once schedule succeeds, the absolute next time to execute.
56 57 58 |
# File 'lib/iyyov/task.rb', line 56 def next_time @next_time end |
#period ⇒ Object
Regular interval between subsequent executions in seconds.
Numeric (default: nil, use fixed_times)
30 31 32 |
# File 'lib/iyyov/task.rb', line 30 def period @period end |
Instance Method Details
#filter(rc) ⇒ Object
144 145 146 |
# File 'lib/iyyov/task.rb', line 144 def filter( rc ) rc.is_a?( Symbol ) ? rc : :continue end |
#next_fixed_time(now) ⇒ Object
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/iyyov/task.rb', line 169 def next_fixed_time( now ) day = Date.civil( now.year, now.month, now.day ) last = day + 7 ntime = nil while ntime.nil? && day <= last if fixed_days.include?( day.wday ) Array( fixed_times ).each do |ft| ft = time_on_date( day, Time.parse( ft, now ) ) ntime = ft if ( ( ft > now ) && ( ntime.nil? || ft < ntime ) ) end end day += 1 end ntime end |
#next_time_to_s ⇒ Object
165 166 167 |
# File 'lib/iyyov/task.rb', line 165 def next_time_to_s @next_time.strftime( '%Y-%m-%dT%H:%M:%S' ) if @next_time end |
#run ⇒ Object
Execute the task, after which the task will be scheduled again in period time or for the next of fixed_times, unless :stop is returned.
90 91 92 93 94 95 96 97 98 99 |
# File 'lib/iyyov/task.rb', line 90 def run rc = :continue if mode == :async rc = test_async_return_code run_thread if rc == :continue else rc = run_direct end rc end |
#run_direct ⇒ Object
133 134 135 136 137 138 139 140 141 142 |
# File 'lib/iyyov/task.rb', line 133 def run_direct @log.debug "Running." begin rc = ( @block.call( self ) if @block ) filter( rc ) rescue StandardError => e @log.error( "Handled and stopped with: ", e ) :stop end end |
#run_thread ⇒ Object
119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/iyyov/task.rb', line 119 def run_thread Thread.new do if @lock.try_lock begin @async_rc = run_direct ensure @lock.unlock end else @log.warn "Already running, skipping this run." end end end |
#schedule(now) ⇒ Object
Determine next_time from now based on period or fixed_times
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/iyyov/task.rb', line 149 def schedule( now ) @next_time = nil if fixed_times @next_time = next_fixed_time( now ) elsif period @next_time = ( now + period ) end if @next_time && ( @next_time - now ) > 60.0 @log.debug { "Next run scheduled @ #{ next_time_to_s }" } end @next_time end |
#test_async_return_code ⇒ Object
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/iyyov/task.rb', line 101 def test_async_return_code rc = :continue # Note: Currently only the main event loop thread goes here and # so the only case for contention is this task already running # in run_thread. In this case we can warn + :skip early. if @lock.try_lock begin rc = @async_rc if ( @async_rc == :stop ) || ( @async_rc == :shutdown ) ensure @lock.unlock end else @log.warn "Already running, (pre) skipping this run." rc = :skip end rc end |
#time_on_date(d, t) ⇒ Object
185 186 187 |
# File 'lib/iyyov/task.rb', line 185 def time_on_date( d, t ) Time.local( d.year, d.month, d.day, t.hour, t.min, t.sec, t.usec ) end |