Cute little simple scheduling code hack


#1

I’m sure there is some far superior prior art out there somewhere, but
this is a useful little hack I threw together today that I thought
someone else might find interesting.

I wanted to do a little task every few seconds for some duration of
time, and after a bit of overkill I came up with a little library that
lets me do stuff like:

every( 5.seconds ).for( 2.days ) { puts “Chunky bacon, k?” }

or

every( 2.minutes ).until ( Time.now + 4.hours ) { dance_for_a_while }

or even

class String
def gradual_out( n = 1 )
ix = 0
every( n.seconds ).unless(lambda {ix >= size}) do
print self[ix].chr
ix += 1
end
end
end

“Tuesday is the new Thursday”.gradual_out( 400.milliseconds )

Fun to play with.
Again, just a quick hack, so if you see any glaring issues or useful
improvements, let me know, because I’m sure I’ll find use for it again
later.

–Code below–

class Scheduler
def initialize( int )
@interval = int
end

def for( secs )
self.until( Time.now + secs ) { |x| yield x }
end

def until( endtime )
self.unless( lambda { Time.now >= endtime } ) { |x| yield x }
end

def unless( cond )
while !cond.call do
current = Time.now
yield current
wait_time = (current + @interval) - Time.now
begin
sleep( wait_time ) unless wait_time <= 0 or cond.call
rescue Interrupt
break
end
end
end
end

module Kernel
def every( int )
Scheduler.new( int )
end
end

class Numeric
def seconds; self; end
def minutes; self * 60; end
def hours; self.minutes * 60; end
def milliseconds; self / 1000.0; end
def days; self.hours * 24; end
end


#2

2007/2/23, KCons removed_email_address@domain.invalid:

or
ix += 1
end
end
end

“Tuesday is the new Thursday”.gradual_out( 400.milliseconds )

Hi,

I had come up with that :

http://openwferu.rubyforge.org/scheduler.html

advantage : one thread for all the tasks
disadvantage : has to wake up to pool its jobqueue

But your approach is definitely more cute and more ‘rubystic’.

Quick question : is the “rescue Interrupt” really needed ? Does it
avoid some “under the carpet thread problems” ?

Best regards,


#3

I had come up with that :

http://openwferu.rubyforge.org/scheduler.html

Neat, that’ll certainly come in handy when I’m doing more complicated
scheduling.
Clean interface, too.

Quick question : is the “rescue Interrupt” really needed ? Does it
avoid some “under the carpet thread problems” ?
Y’know, I imagine the ‘rescue Interrupt’ business is not actually
needed. It is just there because I got seeing exception dumps when I
Ctrl-C’d out of the sleep. :slight_smile:


#4

On Fri, 23 Feb 2007, John M. wrote:

Hi,

I had come up with that :

http://openwferu.rubyforge.org/scheduler.html

looks very interesting!

advantage : one thread for all the tasks disadvantage : has to wake up to
pool its jobqueue

hmmm. is that even possible?

 harp :~/openwferu/trunk/openwfe-ruby > cat a.rb
 require "time"
 require "openwfe/util/otime"
 require "openwfe/util/scheduler"
 include OpenWFE

 scheduler = Scheduler.new

 i = -1

 scheduler.schedule('*/1 * * * *') do
   4.times{ puts Time.now.iso8601(2); sleep 30 }  ### this takes 

120s!
puts(i += 1)
end

 scheduler.sstart

 STDIN.gets



 harp :~/openwferu/trunk/openwfe-ruby > RUBYLIB=lib ruby a.rb
 2007-02-23T08:29:00.22-07:00
 2007-02-23T08:29:30.22-07:00
 2007-02-23T08:30:00.22-07:00
 2007-02-23T08:30:30.22-07:00
 0
 2007-02-23T08:31:00.47-07:00
 2007-02-23T08:31:30.47-07:00
 2007-02-23T08:32:00.47-07:00
 2007-02-23T08:32:30.47-07:00
 1
 2007-02-23T08:33:00.73-07:00
 2007-02-23T08:33:30.73-07:00
 2007-02-23T08:34:00.73-07:00
 2007-02-23T08:34:30.73-07:00
 2
 2007-02-23T08:35:00.98-07:00
 2007-02-23T08:35:30.98-07:00
 2007-02-23T08:36:00.98-07:00
 2007-02-23T08:36:30.98-07:00
 3
 2007-02-23T08:38:00.23-07:00
 2007-02-23T08:38:30.23-07:00
 ...
 ...
 ...

it seems like a single threaded/processed scheduler is an imposibility?

nevertheless i’ve already found a use for this code in a situation where
i
don’t care if events are fired precisely (as is possible) as i declare
them or
not.

cheers.

-a


#5

2007/2/24, removed_email_address@domain.invalid removed_email_address@domain.invalid:

 harp :~/openwferu/trunk/openwfe-ruby > RUBYLIB=lib ruby a.rb
 2007-02-23T08:29:00.22-07:00
 2007-02-23T08:29:30.22-07:00
 2007-02-23T08:30:00.22-07:00
 2007-02-23T08:30:30.22-07:00
 0

it seems like a single threaded/processed scheduler is an imposibility?

Hey, thanks for the light, I’ll fix that / make it better.

I’ll have to correct from “one thread for all tasks” to something like
“one thread as an alarm clock for all tasks”.

nevertheless i’ve already found a use for this code in a situation where i
don’t care if events are fired precisely (as is possible) as i declare them or
not.

Glad to read that.

Cheers,


#6

On 23/02/2007, at 5:35 PM, KCons wrote:

I’m sure there is some far superior prior art out there somewhere, but
this is a useful little hack I threw together today that I thought
someone else might find interesting.

It is interesting! You need to blog about it somewhere so I can
bookmark it for later. :slight_smile:

Pete Y.
http://notahat.com/


#7

KCons wrote:

or
ix += 1
later.

Hello KCons:

Wow… I’m just (8 hours into both) learning Python and Ruby and I
didn’t realize how powerful / extensible Ruby was until I saw your
example. Great stuff!

Thanks,

Michael