Runnin code at a certain time?


#1

Hello all,
I am new to ruby and I am attempting to run some code at a certain
time. The Ruby Time class is very interesting, you can add time, and do
all of these amazing things but i cannot find a way to run code at a
certain time. I feel like I’m missing something. So far all I have is:

sleep(1) while Time.now < (“Time”)

How would I link some code to be run to this? Or is there an easier way?


#2

On 5/25/09, Tom R. removed_email_address@domain.invalid wrote:

Hello all,
I am new to ruby and I am attempting to run some code at a certain
time. The Ruby Time class is very interesting, you can add time, and do
all of these amazing things but i cannot find a way to run code at a
certain time. I feel like I’m missing something. So far all I have is:

sleep(1) while Time.now < (“Time”)

How would I link some code to be run to this? Or is there an easier way?

The proper answer depends on the context where this code will be used.
Do you want your whole program to stop until some target time? In that
case, something as simple as

sleep(target_time-Time.now)
code_to_be_delayed

will do the trick nicely. But if this code runs within the context of
some larger system, which cannot afford to have the whole program be
unable to respond to events for many seconds in a row (rails, for
example), then sleep is a bad idea. In some cases, you might be able
to put your sleep and code_to_be_delayed in another thread, but then
you run into the problem of thread synchronization. If neither of my
simple suggestions does the trick, you should post more details abut
your application. (Maybe then someone will have enough information to
make a specific suggestion… I doubt I will.)


#3

On Tue, 2009-05-26 at 05:36 +0900, Caleb C. wrote:

I am new to ruby and I am attempting to run some code at a certain
time. The Ruby Time class is very interesting, you can add time, and do
all of these amazing things but i cannot find a way to run code at a
certain time. I feel like I’m missing something. So far all I have is:

sleep(1) while Time.now < (“Time”)

How would I link some code to be run to this? Or is there an easier way?

You might want to try my Scheduler gem.

Scheduler.at_time(time_in_seconds_from_epoch) do

… stuff to do …

end

-mental


#4

On 5/25/09, Tom R. removed_email_address@domain.invalid wrote:

end
end
test = TestClass.new
test.testtime(“11:04:40 AM”)

The problems are #1. I don’t know how to link the time code to the code
to be run when the time code is fulfilled.

I think procs are the feature you want to know about here.

#2. If I have a list of times
to be run, and one time is out of order, it will just sleep past the out
of order time.

so, sort 'em.

#3. While the code is waiting for a certain time, with
sleep, it cannot do anything else.

Select, or threads, or some kind of event driven system like
EventMachine are the usual solutions to this problem. I forgot to
mention select before.

Is there a way that I can run code
that will watch for a time to be fulfilled on many levels instead of
just waiting until a time, moving on and waiting for the next? Is it
possible to do something like this:

when test.testtime is true/finished?
run some code
end

Well, in general what you want here is a timer. It’s very easy to
write your own; it sounds like you’re close now, you just need to
learn about sort.

In some cases, you might be able
to put your sleep and code_to_be_delayed in another thread, but then
you run into the problem of thread synchronization.

How would I do this?

Hmm, you have some learning to do. Including how to find information
about the standard library. I suggest you make friends with ri, which
is the command-line tool that displays stdlib documentation. Google
can also be very helpful. You also need some general background on
ruby and programming concepts; I’d suggest the book ‘programming
ruby’. There’s a free version of an old edition online.


#5

Caleb C. wrote:

On 5/25/09, Tom R. removed_email_address@domain.invalid wrote:

Hello all,
I am new to ruby and I am attempting to run some code at a certain
time. The Ruby Time class is very interesting, you can add time, and do
all of these amazing things but i cannot find a way to run code at a
certain time. I feel like I’m missing something. So far all I have is:

sleep(1) while Time.now < (“Time”)

How would I link some code to be run to this? Or is there an easier way?

The proper answer depends on the context where this code will be used.
Do you want your whole program to stop until some target time?
But if this code runs within the context of
some larger system, which cannot afford to have the whole program be
unable to respond to events for many seconds in a row (rails, for
example), then sleep is a bad idea.

Well, I’m not really sure. The intent is to have a repetitive code ran
at quite a few different times with changing variables. The sleep option
doesn’t really seem reliable and realistic, although its the only thing
so far. The code I can come up with is this:

class TestClass
def testtime(timetorun)
timetorun = @timetorun
sleep(1) while Time.now.strftime("%I:%M:%S %p") < ("#{@timetorun}")
#Somewhere code to run when Time.now = timetorun
end
end
test = TestClass.new
test.testtime(“11:04:40 AM”)

The problems are #1. I don’t know how to link the time code to the code
to be run when the time code is fulfilled. #2. If I have a list of times
to be run, and one time is out of order, it will just sleep past the out
of order time. #3. While the code is waiting for a certain time, with
sleep, it cannot do anything else. Is there a way that I can run code
that will watch for a time to be fulfilled on many levels instead of
just waiting until a time, moving on and waiting for the next? Is it
possible to do something like this:

when test.testtime is true/finished?
run some code
end

In some cases, you might be able
to put your sleep and code_to_be_delayed in another thread, but then
you run into the problem of thread synchronization.

How would I do this?

Your example of

sleep(target_time-Time.now)
code_to_be_delayed

seems to work better, although it still shuts the whole code down for a
while.


#6

On May 25, 3:40 pm, Tom R. removed_email_address@domain.invalid wrote:

def testtime(timetorun)
to be run, and one time is out of order, it will just sleep past the out

In some cases, you might be able
seems to work better, although it still shuts the whole code down for a
while.

I’m totally new to Ruby so I’m sorry for the piggyback question but,
in Perl you could
set an alarm clock that’d leave the program unfettered:

{ local $SIG{ALRM} = sub { die “timeout” };
alarm( “target_time” - “Time.now” );
# do other things
alarm( 0 );
};
if ( $@ =~ /^timeout/ ) {# time’s up… }
elsif ( $@ ) {# other error… }

How would Ruby do this?

Thanks,


#7

Caleb C. wrote:

};
So the equivalent of the perl code you posted should be:
#other error
end

Timeout uses Thread#raise, which I think is not reliable on JRuby or
other implementations that use native threads.

PS: does anyone know why Timeout::Error < Interrupt ? Interrupt is for
^C… why would you want timeouts to be handled like ^C?

may be of interest
http://rubyforge.org/projects/rubycron/


#8

Caleb C. wrote:

};
So the equivalent of the perl code you posted should be:
#other error
end

Timeout uses Thread#raise, which I think is not reliable on JRuby or
other implementations that use native threads.

PS: does anyone know why Timeout::Error < Interrupt ? Interrupt is for
^C… why would you want timeouts to be handled like ^C?

also
http://www.notwork.org/~gotoken/ruby/p/crontab/crontab/crontab.rb


#9

On 5/27/09, Anonymous removed_email_address@domain.invalid wrote:

if ( $@ =~ /^timeout/ ) {# time’s up… }
elsif ( $@ ) {# other error… }

How would Ruby do this?

I went and looked again, and there is a Timeout module in ruby’s
stdlib, which I had forgotten about:
http://www.ruby-doc.org/stdlib/libdoc/timeout/rdoc/index.html

So the equivalent of the perl code you posted should be:

#UNTESTED!!!
require ‘timeout’
begin
Timeout.timeout(target_time-Time.now){
#do other things
}
rescue Timeout::Error
#time’s up
rescue Exception
#other error
end

Timeout uses Thread#raise, which I think is not reliable on JRuby or
other implementations that use native threads.

PS: does anyone know why Timeout::Error < Interrupt ? Interrupt is for
^C… why would you want timeouts to be handled like ^C?


#10

Caleb C. wrote:

Timeout uses Thread#raise, which I think is not reliable on JRuby or
other implementations that use native threads.

It should be reliable, and in fact we reimplemented Timeout in Java to
reduce the cost almost down to zero. I don’t like that things like raise
and kill and Timeout are used, but we’ve made sure they work well when
they are.

PS: does anyone know why Timeout::Error < Interrupt ? Interrupt is for
^C… why would you want timeouts to be handled like ^C?

I do not.

  • Charlie

#11

I’ve used rufus-scheduler gem to achieve this functionality:
http://rufus.rubyforge.org/rufus-scheduler/

Jarmo


#12

On 5/28/09, Charles Oliver N. removed_email_address@domain.invalid wrote:

Caleb C. wrote:

Timeout uses Thread#raise, which I think is not reliable on JRuby or
other implementations that use native threads.

It should be reliable, and in fact we reimplemented Timeout in Java to
reduce the cost almost down to zero. I don’t like that things like raise
and kill and Timeout are used, but we’ve made sure they work well when
they are.

I thought you’d made some long blog post proving how it’s impossible
to Thread#raise perfectly reliably in JRuby. I may be confused. I’m
glad to hear that it does work and I apologize for spreading
misinformation.


#13

Jarmo P. wrote:

I’ve used rufus-scheduler gem to achieve this functionality:
http://rufus.rubyforge.org/rufus-scheduler/

Jarmo

Thank you for this awesome gem, it looks to be almost exactly what i
need!


#14

On May 25, 2009, at 13:36, Caleb C. wrote:

How would I link some code to be run to this? Or is there an easier
way?

The proper answer depends on the context where this code will be used.
Do you want your whole program to stop until some target time? In that
case, something as simple as

sleep(target_time-Time.now)
code_to_be_delayed

will do the trick nicely.

Note that #sleep won’t necessarily sleep as long as you like (second
sentence):

$ ri Kernel#sleep
----------------------------------------------------------- Kernel#sleep
sleep([duration]) => fixnum

  From Ruby 1.8

#15

On May 29, 2009, at 12:49, Caleb C. wrote:

 Suspends the current thread for duration seconds (which may be  

any
number, including a Float with fractional seconds). Returns the
actual number of seconds slept (rounded), which may be less than
that asked for if another thread calls Thread#run. Zero
arguments
causes sleep to sleep forever.
[…]

Is there some particular danger that Thread#run will be called on my
threads without my asking?

If it’s library code, yes. If it’s application code, probably not.


#16

On 5/30/09, Eric H. removed_email_address@domain.invalid wrote:

Is there some particular danger that Thread#run will be called on my
threads without my asking?

If it’s library code, yes. If it’s application code, probably not.

Can you be more specific? I’m curious as to how exactly this could
happen. I suspect you speak from experience, but I can’t see how if an
application fiddles with a libraries internals in this way, that’s not
considered a bug in the application.


#17

On 5/28/09, Eric H. removed_email_address@domain.invalid wrote:

sentence):
that asked for if another thread calls Thread#run. Zero arguments
causes sleep to sleep forever.
[…]

Is there some particular danger that Thread#run will be called on my
threads without my asking?


#18

On 5/30/09, Eric H. removed_email_address@domain.invalid wrote:

considered a bug in the application.

Since threads are involved, it doesn’t need to muck with any
internals, it just has to wake up the thread your sleep was running in:

The only purpose of run is to break a call to sleep (or select, or
join. Anything else?) If code external to my library decides to call
run on me, it ought to know what it’s doing. If something bad happens,
it seems to me that that’s a bug in the external code.

   # ...

end
What application actually does this?


#19

On May 30, 2009, at 12:46, Caleb C. wrote:

On 5/30/09, Eric H. removed_email_address@domain.invalid wrote:

Is there some particular danger that Thread#run will be called on my
threads without my asking?

If it’s library code, yes. If it’s application code, probably not.

Can you be more specific? I’m curious as to how exactly this could
happen. I suspect you speak from experience, but I can’t see how if an
application fiddles with a libraries internals in this way, that’s not
considered a bug in the application.

Since threads are involved, it doesn’t need to muck with any
internals, it just has to wake up the thread your sleep was running in:

class YourLib
def your_sleep
sleep 1_000_000
end
end

class MyApp

def do_stuff
@threads << Thread.start do
# …
YourLib.new.your_sleep
# …
end
end

def wakeup
@threads.each do |thread|
thread.run
end
end
end


#20

On 31 May 2009, at 13:00, Caleb C. wrote:

happen. I suspect you speak from experience, but I can’t see how
join. Anything else?) If code external to my library decides to call
run on me, it ought to know what it’s doing. If something bad happens,
it seems to me that that’s a bug in the external code.

In general if you’re writing a library that makes use of threads it’s
your responsibility to make them behave correctly when ‘interrupted’
by application code. Otherwise you have a fragile library that will
greatly complicate debugging for its users.

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net

raise ArgumentError unless @reality.responds_to? :reason