Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

add restartable timer class for ruby

  • Loading branch information...
commit 58e8c3eb28d8bfc0382d33ecfe3e82f5b46e7a1e 1 parent 6c79977
@adzap authored
Showing with 121 additions and 1 deletion.
  1. +33 −0 lib/em/timers.rb
  2. +36 −1 lib/eventmachine.rb
  3. +52 −0 tests/test_timers.rb
View
33 lib/em/timers.rb
@@ -54,4 +54,37 @@ def fire # :nodoc:
end
end
end
+
+ # Creates a restartable timer
+ #
+ # puts "started timer at #{Time.now}"
+ # timer = EventMachine::RestartableTimer.new(5) do
+ # # should be about 7 seconds later, due to restart at 2 seconds
+ # puts "completed timer at #{Time.now}"
+ # end
+ # EventMachine::Timer.new(2) { timer.restart }
+ #
+ class RestartableTimer < Timer
+ def initialize(interval, callback=nil, &block)
+ @interval = interval
+ @code = callback || block
+ @work = method(:fire)
+ schedule
+ end
+
+ # Restart the timer
+ def restart
+ cancel
+ schedule
+ end
+
+ def schedule
+ @signature = EventMachine::add_timer(@interval, @work)
+ end
+
+ def fire
+ @code.call
+ end
+ end
+
end
View
37 lib/eventmachine.rb
@@ -349,6 +349,41 @@ def self.add_periodic_timer *args, &block
EventMachine::PeriodicTimer.new(interval, code)
end
+ # EventMachine#add_restartable_timer adds a restartable timer to the event loop.
+ # It takes the same parameters as the one-shot timer method, EventMachine#add_timer.
+ # This method schedules execution of the given block for a one-shot timer, but can
+ # be restarted before firing to begin the timer from the start of the interval again.
+ #
+ # A restartable timer can be restarted as many times as required, as long as the timer
+ # has not completed. It can also be cancelled like a regular timer.
+ #
+ # === Usage example
+ #
+ # The following sample program creates a restartable and then restarts the timer at
+ # some later time with another shorter timer. The time to complete the restartable
+ # will be the original interval plus the amount of time passed before being restarted.
+ #
+ # EventMachine::run {
+ # puts "Starting the run now: #{Time.now}"
+ # timer = EventMachine::add_restartable_timer( 5 ) {
+ # puts "Executing timer event: #{Time.now}"
+ # }
+ # EventMachine::add_timer( 2 ) {
+ # puts "Restarting timer: #{Time.now}"
+ # timer.restart
+ # }
+ # }
+ #
+ #
+ # Also see EventMachine::RestartableTimer
+ #
+ def self.add_restartable_timer *args, &block
+ interval = args.shift
+ code = args.shift || block
+
+ EventMachine::RestartableTimer.new(interval, code)
+ end
+
# Cancel a timer using its signature. You can also use EventMachine::Timer#cancel
#
def self.cancel_timer timer_or_sig
@@ -1543,4 +1578,4 @@ def self.klass_from_handler(klass = Connection, handler = nil, *args)
# Save everyone some typing.
EM = EventMachine
-EM::P = EventMachine::Protocols
+EM::P = EventMachine::Protocols
View
52 tests/test_timers.rb
@@ -119,6 +119,58 @@ def test_periodic_timer_self_cancel
assert( x == 4 )
end
+ def test_restartable_timer
+ x = false
+ EventMachine.run {
+ EventMachine::RestartableTimer.new(0.1) do
+ x = true
+ EventMachine.stop
+ end
+ }
+ assert x
+ end
+
+ def test_add_restartable_timer
+ x = false
+ EventMachine.run {
+ rt = EventMachine.add_restartable_timer(0.1) { x = true }
+ assert rt.respond_to?(:restart)
+ EventMachine.stop
+ }
+ end
+
+ def test_restart_restartable_timer
+ x = false
+ EventMachine.run {
+ EventMachine.add_timer(0.4) { x = 1 }
+ rt = EventMachine::RestartableTimer.new(0.3) do
+ x = true
+ end
+ EventMachine.add_timer(0.2) { rt.restart }
+ EventMachine.add_timer(0.6) { EventMachine.stop }
+ }
+ assert x == true
+ end
+
+ def test_restartable_timer_cancel
+ x = false
+ EventMachine.run {
+ rt = EventMachine::RestartableTimer.new(0.3) { x = true }
+ rt.cancel
+ EventMachine::Timer.new(0.1) { EventMachine.stop }
+ }
+ assert !x
+ end
+
+ def test_add_restartable_timer_cancel
+ x = false
+ EventMachine.run {
+ rt = EventMachine.add_restartable_timer(0.2) { x = true }
+ EventMachine.cancel_timer(rt)
+ EventMachine.add_timer(0.3) { EventMachine.stop }
+ }
+ assert !x
+ end
# This test is only applicable to compiled versions of the reactor.
# Pure ruby and java versions have no built-in limit on the number of outstanding timers.
Please sign in to comment.
Something went wrong with that request. Please try again.