Class: Symphony::Metronome::ScheduledEvent
- Inherits:
-
Object
- Object
- Symphony::Metronome::ScheduledEvent
- Extended by:
- Configurability, Loggability
- Includes:
- Comparable
- Defined in:
- lib/symphony/metronome/scheduledevent.rb
Overview
A class the represents the relationship between an interval and an event.
Constant Summary collapse
- CONFIG_DEFAULTS =
Configure defaults.
{ :db => 'sqlite:///tmp/metronome.db', :splay => 0 }
Class Attribute Summary collapse
-
.db ⇒ Object
readonly
A Sequel-style DB connection URI.
-
.splay ⇒ Object
readonly
Adjust recurring intervals by a random window.
Instance Attribute Summary collapse
-
#ds ⇒ Object
readonly
The sequel dataset representing this event.
-
#event ⇒ Object
readonly
The parsed interval expression.
-
#id ⇒ Object
readonly
The unique ID number of the scheduled event.
-
#options ⇒ Object
readonly
The options hash attached to this event.
-
#runtime ⇒ Object
readonly
The exact time that this event will run.
Class Method Summary collapse
-
.configure(config = nil) ⇒ Object
Configurability API.
-
.load ⇒ Object
Return a set of all known events, sorted by date of execution.
Instance Method Summary collapse
-
#<=>(other) ⇒ Object
Comparable interface, order by next run time, soonest first.
-
#delete ⇒ Object
Permanently remove this event from the database.
-
#fire ⇒ Object
Perform the action attached to the event.
-
#initialize(row) ⇒ ScheduledEvent
constructor
Create a new ScheduledEvent object.
-
#reset_runtime ⇒ Object
Set the datetime that this event should fire next.
Constructor Details
#initialize(row) ⇒ ScheduledEvent
Create a new ScheduledEvent object.
97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/symphony/metronome/scheduledevent.rb', line 97 def initialize( row ) @event = Symphony::Metronome::IntervalExpression.parse( row[:expression], row[:created] ) = row.delete( :options ) @id = row.delete( :id ) @ds = self.class.db[ :metronome ].filter( :id => self.id ) self.reset_runtime unless self.class.splay.zero? splay = Range.new( - self.class.splay, self.class.splay ) @runtime = self.runtime + rand( splay ) end end |
Class Attribute Details
.db ⇒ Object (readonly)
A Sequel-style DB connection URI.
33 34 35 |
# File 'lib/symphony/metronome/scheduledevent.rb', line 33 def db @db end |
.splay ⇒ Object (readonly)
Adjust recurring intervals by a random window.
36 37 38 |
# File 'lib/symphony/metronome/scheduledevent.rb', line 36 def splay @splay end |
Instance Attribute Details
#ds ⇒ Object (readonly)
The sequel dataset representing this event.
112 113 114 |
# File 'lib/symphony/metronome/scheduledevent.rb', line 112 def ds @ds end |
#event ⇒ Object (readonly)
The parsed interval expression.
115 116 117 |
# File 'lib/symphony/metronome/scheduledevent.rb', line 115 def event @event end |
#id ⇒ Object (readonly)
The unique ID number of the scheduled event.
118 119 120 |
# File 'lib/symphony/metronome/scheduledevent.rb', line 118 def id @id end |
#options ⇒ Object (readonly)
The options hash attached to this event.
121 122 123 |
# File 'lib/symphony/metronome/scheduledevent.rb', line 121 def end |
#runtime ⇒ Object (readonly)
The exact time that this event will run.
124 125 126 |
# File 'lib/symphony/metronome/scheduledevent.rb', line 124 def runtime @runtime end |
Class Method Details
.configure(config = nil) ⇒ Object
Configurability API.
46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/symphony/metronome/scheduledevent.rb', line 46 def self::configure( config=nil ) config = self.defaults.merge( config || {} ) @db = Sequel.connect( config.delete(:db) ) @splay = config.delete( :splay ) # Ensure the database is current. # migrations_dir = Symphony::Metronome::DATADIR + 'migrations' unless Sequel::Migrator.is_current?( self.db, migrations_dir.to_s ) Loggability[ Symphony ].info "Installing database schema..." Sequel::Migrator.apply( self.db, migrations_dir.to_s ) end end |
.load ⇒ Object
Return a set of all known events, sorted by date of execution. Delete any rows that are invalid expressions.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/symphony/metronome/scheduledevent.rb', line 64 def self::load now = Time.now events = SortedSet.new # Force reset the DB handle. self.db.disconnect self.log.debug "Parsing/loading all actions." self.db[ :metronome ].each do |event| begin event = new( event ) events << event rescue ArgumentError, Symphony::Metronome::TimeParseError => err self.log.error "%p while parsing \"%s\": %s" % [ err.class, event[:expression], err. ] self.log.debug " " + err.backtrace.join( "\n " ) self.db[ :metronome ].filter( :id => event[:id] ).delete end end return events end |
Instance Method Details
#<=>(other) ⇒ Object
Comparable interface, order by next run time, soonest first.
212 213 214 |
# File 'lib/symphony/metronome/scheduledevent.rb', line 212 def <=>( other ) return self.runtime <=> other.runtime end |
#delete ⇒ Object
Permanently remove this event from the database.
204 205 206 207 |
# File 'lib/symphony/metronome/scheduledevent.rb', line 204 def delete self.log.debug "Removing action %p" % [ self.id ] self.ds.delete end |
#fire ⇒ Object
Perform the action attached to the event. Yields the deserialized options, the action ID to the supplied block if this event is okay to execute.
If the event is recurring, perform additional checks against the last run time.
Automatically remove the event if it has expired.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/symphony/metronome/scheduledevent.rb', line 169 def fire rv = self.event.fire? # Just based on the expression parser, is this event ready to fire? # if rv opts = Yajl.load( self. ) # Don't fire recurring events unless their interval has elapsed. # This prevents events from triggering when the daemon receives # a HUP. # if self.event.recurring now = Time.now row = self.ds.first if row last = row[ :lastrun ] return false if last && now - last < self.event.interval end # Mark the time this recurring event was fired. self.ds.update( :lastrun => Time.now ) end yield opts, self.id end self.delete if rv.nil? return rv end |
#reset_runtime ⇒ Object
Set the datetime that this event should fire next.
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/symphony/metronome/scheduledevent.rb', line 129 def reset_runtime now = Time.now # Start time is in the future, so it's sufficent to be considered the run time. # if self.event.starting >= now @runtime = self.event.starting return end # Otherwise, the event should already be running (start time has already # elapsed), so schedule it forward on it's next interval iteration. # # If it's a recurring event that has run before, consider the elapsed time # as part of the next calculation. # row = self.ds.first if self.event.recurring && row last = row[ :lastrun ] if last && now > last @runtime = now + self.event.interval - ( now - last ) else @runtime = now + self.event.interval end else @runtime = now + self.event.interval end end |