views:

75

answers:

4

I want to run my ruby script x times a day (the number might change) on my linux box. What would be the best way to do so if I do not want it to happen at the same time? I want the time (hour and minute) to be random

I was thinking of using at command. The script would be called by at in x hours/minutes or so and then the script would set up another call by at. Not sure if there is any better way or only ruby way.

A: 

I guess you can setup a cronjob that calls on a bash script which delays execution by a random time but I don't know if you can do it somehow inside the cronjob. You can find some information on how to do that on this site and if you don't know about crontab and cronjobs you can find more information about that here.

Hultner
+5  A: 

I'd consider using the at program to run the programs (instead of using cron directly, because cron really only works on a fixed schedule). I'd also create a program (I'd use Perl; you'll use Ruby) to schedule a random delay until the next time the job is executed.

You'll need to consider whether it is crucial that the job is executed 'x' times in 24 hours, and how the randomness should work. What is the range of variation in times. For example, you might have a cron job run at midnight plus 7 minutes, say, which then schedules 'x' at jobs spaced evenly through the day, with a random deviation in the schedule of ±30 minutes. Or you might prefer an alternative that schedules a the jobs with an average gap of 24/x hours and a random deviation of some amount. The difference is that the first mechanism guarantees that you get x events in the day (unless you make things too extreme); the second might sometimes only get x-1 events, or x+1 events, in 24 hours.

Jonathan Leffler
A: 

If you want to run X times a day, set your crontab entry to:

0 */X * * * command_to_run

where X is the hourly interval you want to fire your job on to get the desired number of executions/day. For instance, use 2 to fire off every two hours for a total of 12 executions/day.

In your code use this at the top to force it to sleep a random time up to that cron interval:

# How long the program takes to run, in seconds. Be liberal unless having
# two instances running is OK.
EXECUTION_TIME = 10 

INTERVAL = 2 * 60 * 60 - EXECUTION_TIME

sleep(rand(INTERVAL))

The idea is that cron will start your program at a regular interval, but then it will sleep some random number of seconds within that interval before continuing.

Change the value for EXECUTION_TIME to however long you think it will take for the code to run, to give it a chance to finish before the next interval occurs. Change the "2" in the INTERVAL to whatever your cron interval is.

I haven't tested this but it should work, or at least get you on the right path.

Greg
does `sleep` take any CPU time/power?
Radek
@Radek: no; sleep is essentially 'free' in terms of CPU time.
Jonathan Leffler
As a note: This might produce x-1 runs a day since the process can be started before midnight and then sleep until after midnight.
dbemerlin
@dbemerlin, I think if the intervals are set up correctly there is no chance of it wrapping past midnight. For instance, if the cron fires at */2, the last time in the day that the run occurs would be 10PM. If the interval is set correctly in the code it would run sometime after sleeping 0 - 7200 seconds minus the expected run-time which would still be before midnight, resulting in the correct number of runs in the day.
Greg
@Radek, Jonathan is correct. Sleep tells the OS to ignore the code until the sleep interval expires. It's the recommended way to pause code for a period of time.
Greg
+1  A: 

I think scheduler solutions are bit limiting, to get most flexible random action, turn your script to daemon and code the loop / wait yourself.

For Ruby there seems to be this: http://raa.ruby-lang.org/project/daemons/

Harriv
I like this one. I was thinking of something like that ...
Radek
You might want to compare the ease of setup of sleep() vs. setting up a daemon, then compare the coding of a loop with a sleep vs. simply sleeping. I'm lazy and would tell the code to sleep the random amount of time.
Greg