user866364
user866364

Reputation:

Cron expression to run every N minutes

I need to build a cron expression to run a job every 10 minutes after the user click on start button.

I'm trying to do something like:

0 42/10 * * * ? *

And 42/10 is like the user click to start at hh:42 (example: 18h42). The next schedule is like:

1.  Friday, March 20, 2015 6:42 PM
2.  Friday, March 20, 2015 6:52 PM
3.  Friday, March 20, 2015 7:42 PM
4.  Friday, March 20, 2015 7:52 PM
5.  Friday, March 20, 2015 8:42 PM

The problem is after second execution, the job waits like a hour to perform the next execution. How can i build a cron expression that starts immediately and after still running after N minutes?

Thank in advance.

Upvotes: 12

Views: 71359

Answers (4)

kvantour
kvantour

Reputation: 26491

If you want to run a cron every n minutes, there are two cases to consider :

  • Every nth minute (60 is divisible by n)
  • Every nth minute starting from minute YYYY-MM-DD HH:MM:00 (generic)

The latter case is a generic case and covers the case where 60 is not divisible by n. It is mentioned that this case needs a "begin-time". With some simple math, you quickly figure why this is.

Every nth minute (60 is divisible by n)

For this we use the combination of defining a range and a step value:

man 5 crontab: Step values can be used in conjunction with ranges. Following a range with /<number> specifies skips of the number's value through the range. For example, 0-23/2 can be used in the 'hours' field to specify command execution for every other hour (the alternative in the V7 standard is 0,2,4,6,8,10,12,14,16,18,20,22). Step values are also permitted after an asterisk, so if specifying a job to be run every two hours, you can use */2.

See the following examples:

# Example of job definition:
# .----------------- minute (0 - 59)
# |   .------------- hour (0 - 23)
# |   |  .---------- day of month (1 - 31)
# |   |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |   |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
# |   |  |  |  |
# *   *  *  *  *   command to be executed
  m/n *  *  *  *   command1

Here, command1 will be executed every nth minute from m till 59.

This means that :

  • if m<=n, they will always be spaced by n minutes. Eg. m=2,n=10 :: the job will run on minutes 2,12,22,32,42,52
  • if m>n, they will always be spaced by n minutes, except at the start of the hour. Eg. m=12,n=10 :: the job will run on minutes 12,22,32,42,52. So here we have a jump of 20 minutes between the 52nd and 12th minute.

note: you clearly see that if n does not divide 60 perfectly, you will have problems. Eg. m=0,n=11 runs on 0,11,22,33,44,55, so we only have 5 minutes to the next run and not 11.

Every nth minute starting from minute YYYY-MM-DD HH:MM:00

This case is generic and covers the non-divisibility of 60.

Here it gets more interesting and a different approach needs to be made. This can be resolved when you have a continuous counter from a given day. Enter UNIX time stamp, the total seconds since 1970-01-01 00:00:00 UTC. Let's say we want to start from the moment McFly arrived in Riverdale:

% date -d '2015-10-21 07:28:00' +%s 
1445412480

For a cronjob to run every 7th minute after `2015-10-21 07:28:00', the crontab would look like this:

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
# |  |  |  |  |
# *  *  *  *  *   command to be executed
  *  *  *  *  *   mintestcmd "2015-10-21 07:28:00" 7 && command2

with mintestcmd defined as

#!/usr/bin/env bash
starttime=$(date -d "$1" "+%s")
# return UTC time
now=$(date "+%s")
# get the amount of minutes
delta=$(( (now - starttime) / 60 ))
# set the modulo
modulo=$2
# do the test
(( delta % modulo == 0))

Remark: UNIX time is given in UTC. If your cron runs in a different time-zone which is influenced by daylight saving time, it is advisable not to run the command between 2 and 3 o'clock. This could skip the command or run the command twice (depending if the time jumps forward or backwards)

Remark: UNIX time is not influenced by leap seconds

Remark: cron has no sub-second accuracy

Upvotes: 12

Tam
Tam

Reputation: 3987

I found this link, really good: We can get corn expression almost every possible scheduling option:

enter image description here

Please refer above sample screenshot, its really visual control and self explanatory for to generate any cron expression.

Upvotes: 5

Sahil Chhabra
Sahil Chhabra

Reputation: 11706

You can't create the cron expression based on the user input or trigger.

Better solution is use a boolean flag to enable or disable the cron i.e. enable the cron service method when user starts the trigger like below:

public static boolean cronEnabled = false;

public cronServiceMethod(){
  if(cronEnabled){
     // Keep your logic here
  }
}

// Call this method when user clicks the Start button
public enableCron(){
  cronEnabled = true;
}

public disableCron(){
  cronEnabled = false;
}

As far as cron is concerned, make it run every 10 minutes like below:

0 0/10 * * * ?

Upvotes: 0

lsowen
lsowen

Reputation: 3828

I think your format is wrong. The order of the fields is:

  1. Minute
  2. Hour
  3. Day of Month
  4. Month
  5. Day of Week
  6. Command

So in your example, the Minute is 0, and your Hour is invalid (Hour must be in the range 0-23). I'm guessing cron is ignoring the incorrect Hour, and running on Minute 0 of every hour.

However, if you did want to run every N minutes, you could use a format like (where N is less than 60):

0/N * * * * /bin/echo "Your Command Here"

However, keep in mind that the /N repeats the command every N minutes within the current hour. So, if you have 0/33 in your crontab your command will run at:

  • 00:00
  • 00:33
  • 01:00
  • 01:33

Not at:

  • 00:00
  • 00:33
  • 01:06
  • 01:39

Upvotes: 7

Related Questions