Add 'last run' timestamps for recurring events, and take these into
account when firing events on daemon rescheduling (via HUP.) FossilOrigin-Name: 1620e80e8bddd27741569dea0ff4bd84ba29429861ed49d17f5777c238ae4876
This commit is contained in:
parent
b18647f6a5
commit
7c2954b0ad
6 changed files with 79 additions and 8 deletions
11
README.rdoc
11
README.rdoc
|
|
@ -50,7 +50,7 @@ Symphony connection information:
|
|||
|
||||
== Adding Actions
|
||||
|
||||
There are two primary components to Metronome -- getting actions into
|
||||
There are two primary components to Metronome -- getting schedules into
|
||||
its database, and performing some task with those actions when the time
|
||||
is appropriate.
|
||||
|
||||
|
|
@ -76,6 +76,15 @@ starts up or receives a HUP signal, it will re-read and schedule out
|
|||
upcoming work.
|
||||
|
||||
|
||||
== Performing Work
|
||||
|
||||
Calling 'run' on the Metronome class is a blocking call, waking up upon
|
||||
a scheduled event. The run method expects a ruby block, and it receives
|
||||
the payload and the database ID of the scheduled event. Metronome is
|
||||
unopinioned, what you do within this block is entirely up to you. See
|
||||
the Synopsis section above for some examples.
|
||||
|
||||
|
||||
== Options
|
||||
|
||||
Metronome uses
|
||||
|
|
|
|||
1
Rakefile
1
Rakefile
|
|
@ -140,4 +140,5 @@ lib/symphony/metronome/mixins.rb
|
|||
lib/symphony/metronome/intervalexpression.rb
|
||||
lib/symphony/metronome/scheduledevent.rb
|
||||
data/symphony-metronome/migrations/20140419_initial.rb
|
||||
data/symphony-metronome/migrations/20141028_lastrun.rb
|
||||
README.rdoc
|
||||
|
|
|
|||
23
data/symphony-metronome/migrations/20141028_lastrun.rb
Normal file
23
data/symphony-metronome/migrations/20141028_lastrun.rb
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# vim: set nosta noet ts=4 sw=4:
|
||||
|
||||
### Add a 'lastrun' time stamp for recurring events.
|
||||
###
|
||||
class Lastrun < Sequel::Migration
|
||||
|
||||
def initialize( db )
|
||||
@db = db
|
||||
end
|
||||
|
||||
def up
|
||||
if @db.adapter_scheme == :postgres
|
||||
add_column :metronome, :lastrun, timestamptz
|
||||
else
|
||||
add_column :metronome, :lastrun, DateTime
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
drop_column :metronome, :lastrun
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -9,7 +9,7 @@ module Symphony::Metronome
|
|||
Configurability
|
||||
|
||||
# Library version constant
|
||||
VERSION = '0.1.0'
|
||||
VERSION = '0.2.0'
|
||||
|
||||
# Version-control revision constant
|
||||
REVISION = %q$Revision$
|
||||
|
|
@ -74,6 +74,5 @@ module Symphony::Metronome
|
|||
return Symphony::Metronome::Scheduler.run( &block )
|
||||
end
|
||||
|
||||
|
||||
end # Symphony::Metronome
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ class Symphony::Metronome::ScheduledEvent
|
|||
# Configure defaults.
|
||||
#
|
||||
CONFIG_DEFAULTS = {
|
||||
db: 'sqlite:///tmp/metronome.db',
|
||||
splay: 0
|
||||
:db => 'sqlite:///tmp/metronome.db',
|
||||
:splay => 0
|
||||
}
|
||||
|
||||
class << self
|
||||
|
|
@ -52,6 +52,7 @@ class Symphony::Metronome::ScheduledEvent
|
|||
#
|
||||
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
|
||||
|
|
@ -97,6 +98,8 @@ class Symphony::Metronome::ScheduledEvent
|
|||
@event = Symphony::Metronome::IntervalExpression.parse( row[:expression], row[:created] )
|
||||
@options = row.delete( :options )
|
||||
@id = row.delete( :id )
|
||||
@ds = self.class.db[ :metronome ].filter( :id => self.id )
|
||||
|
||||
self.reset_runtime
|
||||
|
||||
unless self.class.splay.zero?
|
||||
|
|
@ -105,6 +108,9 @@ class Symphony::Metronome::ScheduledEvent
|
|||
end
|
||||
end
|
||||
|
||||
# The sequel dataset representing this event.
|
||||
attr_reader :ds
|
||||
|
||||
# The parsed interval expression.
|
||||
attr_reader :event
|
||||
|
||||
|
|
@ -133,21 +139,54 @@ class Symphony::Metronome::ScheduledEvent
|
|||
# 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
|
||||
|
||||
|
||||
### 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.
|
||||
###
|
||||
def fire
|
||||
rv = self.event.fire?
|
||||
|
||||
# Just based on the expression parser, is this event ready to fire?
|
||||
#
|
||||
if rv
|
||||
opts = Yajl.load( self.options )
|
||||
|
||||
# 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
|
||||
last = self.ds.first[ :lastrun ]
|
||||
return false if last && now - last < self.event.interval
|
||||
|
||||
# Mark the time this recurring event was fired.
|
||||
self.ds.update( :lastrun => Time.now )
|
||||
end
|
||||
|
||||
yield opts, self.id
|
||||
end
|
||||
|
||||
|
|
@ -160,7 +199,7 @@ class Symphony::Metronome::ScheduledEvent
|
|||
###
|
||||
def delete
|
||||
self.log.debug "Removing action %p" % [ self.id ]
|
||||
self.class.db[ :metronome ].filter( :id => self.id ).delete
|
||||
self.ds.delete
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class Symphony::Metronome::Scheduler
|
|||
SIGNALS = [ :HUP, :INT, :TERM ]
|
||||
|
||||
CONFIG_DEFAULTS = {
|
||||
:listen => true
|
||||
:listen => false
|
||||
}
|
||||
|
||||
class << self
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue