16

For staggering purposes I am trying to schedule jobs an a 2 minute offset that run every 5 mins. That is I want 1 job to run 1,6,11,16.. and the other one to run at 2,7,12,17...

I couldn't find an example to do this. So I tried:

every 5.minutes, :at=> 1 do
 command "echo 'you can use raw cron sytax too'"
end 

This seems to work but all the ':at' examples look to be expecting a time in a string format. Is the above valid to do or is just happens to work and the every option doesn't really support a starting time.

mrk
  • 4,999
  • 3
  • 27
  • 42
HeretoLearn
  • 7,124
  • 6
  • 24
  • 22

3 Answers3

19

It sounds like you have a dependency between the two jobs, so there are two ways I think you can handle this. If you want to run at 1,6,11,16 and so on, as your question suggests, then simply use raw cron syntax:

every '0,5,10,15,20,25,30,35,40,45,50,55 * * * *' do
  command "echo 'you can use raw cron syntax one'"
end

every '1,6,11,16,21,26,31,36,41,46,51,56 * * * *' do
  command "echo 'you can use raw cron syntax two'"
end

But it's probably better to execute the second job once the first one is done. This should ensure that the jobs don't overlap and that the second only runs when after the first completes.

every 5.minutes do
  command "echo 'one' && echo 'two'"
end
Pan Thomakos
  • 34,082
  • 9
  • 88
  • 85
  • Thanks Pan. Yes, I saw the raw cron syntax support but wanted to avoid writing the whole string out and use whenever to make my job easy. Also there is no dependency on the tasks and there are more than 2. I just want to stagger them so that they all don't run at the same time every hour. – HeretoLearn Jun 13 '11 at 13:45
  • @HeretoLearn whenever doesn't support this kind of syntax in pure ruby, so you'll have to use the raw crontab syntax. If the jobs aren't dependent on each other then I would recommend running them using the first example. – Pan Thomakos Jun 13 '11 at 16:44
11

every expects an integer.

To avoid thundering herd problem, you can do this.

every 5.minutes - 10.seconds do
  command "echo first task"
end

every 5.minutes + 10.seconds do
  command "echo second task"
end

You can randomise the offset too

def some_seconds
  (-10..10).to_a.sample.seconds
end

every 5.minutes + some_seconds do
  command "echo first task"
end

every 5.minutes + some_seconds do
  command "echo second task"
end

Like other answers this won't work for tasks depending on each other. If your tasks depend on each other, you should use rake to handle it for you or run next one manually in your task.

# shedule.rb
every 5.minutes do
  rake 'jobs:last_one'
end

# Rakefile.rb
namespace :jobs do
  task :first_one do
    sh 'first command'
  end

  task second_one: [:first_one] do
    sh 'second_command that_should_run_after_first_one'
  end

  task last_one: [:second_one] do
    sh 'last_command that_should_run_after_all_commands'
  end
end
Pooyan Khosravi
  • 4,861
  • 1
  • 19
  • 20
  • 2
    This looks a more sensible way to solve the problem than the accepted answer. – Epigene Oct 13 '14 at 10:58
  • 1
    This did not work for me as intuitively as I had assumed. `every 15.minutes + 2.minutes do` Turned into this: `17,34,51 * * * *` what I was going for was this: `2,17,32,47 * * * *` Working in Rails 4.2.5 with Whenever gem 0.9.4 – Shadoath Mar 24 '16 at 17:36
2

Yes, that should be valid. Look at https://github.com/javan/whenever/blob/master/lib/whenever/cron.rb

Look at the parse_time method. These lines in particular:

      when 1.hour...1.day
        hour_frequency = (@time / 60 / 60).round
        timing[0] = @at.is_a?(Time) ? @at.min : @at
        timing[1] = comma_separated_timing(hour_frequency, 23)
John Vance
  • 532
  • 4
  • 15
  • This code shows that the 'at' option is only used for 1 hour to 1 day so this unfortunately will NOT work. I looked at the other whenever source code and it appears interval > 1 hr uses at, but under 1 hr does not. – TomDavies Oct 21 '15 at 13:49