Forum: Ruby Runnin code at a certain time?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Tom R. (Guest)
on 2009-05-25 20:42
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?
Caleb C. (Guest)
on 2009-05-26 00:37
(Received via mailing list)
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.)
Mental G. (Guest)
on 2009-05-26 00:49
(Received via mailing list)
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
Tom R. (Guest)
on 2009-05-26 02:40
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.
Caleb C. (Guest)
on 2009-05-26 05:55
(Received via mailing list)
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.
Anonymous (Guest)
on 2009-05-27 20:48
(Received via mailing list)
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,
Caleb C. (Guest)
on 2009-05-28 04:08
(Received via mailing list)
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...

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?
Reid T. (Guest)
on 2009-05-28 05:23
(Received via mailing list)
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/
Reid T. (Guest)
on 2009-05-28 05:24
(Received via mailing list)
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/cro...
Jarmo P. (Guest)
on 2009-05-28 10:13
I've used rufus-scheduler gem to achieve this functionality:
http://rufus.rubyforge.org/rufus-scheduler/

Jarmo
Charles Oliver N. (Guest)
on 2009-05-28 21:22
(Received via mailing list)
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
Caleb C. (Guest)
on 2009-05-28 21:57
(Received via mailing list)
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.
Tom R. (Guest)
on 2009-05-29 03:59
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!
Eric H. (Guest)
on 2009-05-29 04:05
(Received via mailing list)
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
Caleb C. (Guest)
on 2009-05-29 20:50
(Received via mailing list)
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?
Eric H. (Guest)
on 2009-05-30 19:22
(Received via mailing list)
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.
Caleb C. (Guest)
on 2009-05-30 20:52
(Received via mailing list)
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.
Eric H. (Guest)
on 2009-05-30 23:04
(Received via mailing list)
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
Caleb C. (Guest)
on 2009-05-31 21:01
(Received via mailing list)
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?
Eleanor McHugh (Guest)
on 2009-05-31 21:23
(Received via mailing list)
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
This topic is locked and can not be replied to.