Crontab, Meaning of */50 in Minutes Field - cron

OK, I see a crontab line like:
*/50 * * * 1-6 command
Now, if my research is correct, something like */2 makes sense (minutes divided by 2, or every 2 minutes) and */5 makes sense (every 5 minutes).
In fact, the command happens to run at 50 minutes after the hour. Which makes sense as 60/50 is 0 remainder 50. But if that is the desired effect, why not just put 50 instead of */50?
Am I missing something, or did the original programmer just get too clever?
I'd like to just change it to 50, which I believe was the original intent, but I don't want to change anything without understanding the effects.

cron is stateless and does not remember when was the last time it executed a task.
From Wikipedia:
Note that frequencies in general cannot be expressed; only step values
which evenly divide their range express accurate frequencies (for
minutes and seconds, that's /2, /3, /4, /5, /6, /10, /12, /15, /20 and
/30 because 60 is evenly divisible by those numbers; for hours, that's
/2, /3, /4, /6, /8 and /12); all other possible "steps" and all other
fields yield inconsistent "short" periods at the end of the time-unit
before it "resets" to the next minute, second, or day; for example,
entering */5 for the day field sometimes executes after 1, 2, or 3
days, depending on the month and leap year; this is because cron is
stateless (it does not remember the time of the last execution nor
count the difference between it and now, required for accurate
frequency counting—instead, cron is a mere pattern-matcher).

Related

Is there a function for applying a date-diff to a cronexpression?

Suppose that I have a cron job which:
other admins might alter the cronexpression in the future, and
I want to notify users some fixed time (1 day, 2 hours, etc) in advance of every run of the job. It seems possible to construct a function (the particular language is not important to me) which inputs a valid cronexpression and a time difference ("+1d", "-12h", etc) and outputs a cronexpression which has been translated by some time delta (in the same way that many languages have a dateadd() for fixed, individual dates).
Examples:
- cronshift("0 2 12 * *", "-3h") => "0 23 11 * *" # 2am on the 12th
becomes 11pm on the 11th
- cronshift("0 1 * * 0,4", "-24h) => "0 1 * *
3,6" # 1am on Sun,Wed becomes 1am on Tues/Sat
- cronshift("0 1-3 12 *
*", "-2h") => ["0 23 11 * *", "0 0-1 12 * *"] # Extra credit: 1-3am on the 12th must be split across the 11th and 12th
Of course, there are a lot of complications (textual day-of-week names, '/' step values, etc) which I don't really need. Also, parsing the crontab to find/update the notification task is outside of the scope of this question. I also realize that another solution is to just calculate the date of the next cronexpression match, adjust that single date, and then make an at job to do the notification and create a new at job, but I'm intrigued by the complexity of time-shifting a cronexpression. Is there a module in any semi-popular scripting language that already does something like this?
Your are looking for a commercial grade scheduler with monitoring and logging with GUI and Web UI. Like this one.
I remember long ago there was a GUI utility for for cron and at. Named gnome-schedule hope it still exist.
You might also looking into higher-end task schedulers like Puppet and Jenkins
For high end scheduling with dynamic time calculations suggesting to use systemd timers.

Crontab, execute a task a random number of times within a period of time

I want to use cron to run a task a random number of times every 3 minutes and 30 seconds, between 8 a.m. and 6 p.m. They could help me with this problem. I've been searching, but I have not managed to do it. Thank you very much in advance.
I would address the issue two ways - depending on the requirement:
if you mean that a task may be executed or not at random, every 3 minutes and 30 seconds between 8am and 6pm, you can add some random number generation and execute if matches certain criteria (number greater than x or divisible by y, etc)
if you mean that the task should be executed random N times for each trigger occurring every 3 minutes 30 seconds between 8am and 6pm, you could use a random number to specify how many times to execute and then loop until reaching that number of executions.
As for the cron, you may find this page useful to assemble it :)
EDIT
Here a follow-up on the comment, that the use case refers to the second one I mentioned above:
script
random_times=$(( ( RANDOM % 10 ) + 1 ))
for i in `seq 1 $random_times`; do bash /path/to/script.sh; done
crontab
*/3 * * * *
Please notice, that if using unix crontab, you do not have seconds granularity and thus will execute every 3 minutes.

Is the following cron expression means every 45 minutes?

Am willing to run a script every 45 minute (not the :45th minute of every hour)
e.g. 10:00, 10:45, 11:30, 12:15, and so on.
*/45 * * * *
Am not sure this is the correct expression.
I suspect (edit: I'm pretty sure by now) that it doesn't do what you want: fields are separate, and */45 for minutes is nothing more than 0,45. I would use the following three entries if */45 doesn't do the job:
0,45 0-23/3 * * *
30 1-23/3 * * *
15 2-23/3 * * *
If you take a look at entry.c file in vixie cron sources, you'll notice that each field of each entry is parsed by get_list and represented as bitmaps of allowed values for that field. That almost precludes any "smart" interpretation, as the distinction of */45 and 0,45 is lost at this stage... but there is a MIN_STAR flag, set at the presence of * in minutes (including */45). So we take a look at cron.c, a single place where MIN_STAR is examined, to learn it's unrelated to our problem. Now we know for sure that */45 means "every 45th minute of every hour": 0:00, 0:45, 1:00, 1:45 and so on.
There were two answers here confidently stating the opposite, quoting an unfortunate passage in the manual:
Steps are also permitted after an asterisk, so if you want to say
"every two hours", just use "*/2"
We are lucky to have a 24 hour day, containing even number of hours, making "every two hours from 0:00, each day" and "every two hours generally" indistinguishable. Too bad that the manual didn't go far enough to document non-trivial cases, making the impression that * */22 means every 22 hours. It does not. Star with a step is just a shorthand for a list of values in the field where it's used; it doesn't interact with other fields.
At the basic timing of cron, your system checks once per minute to see if there are any cronjobs to run. It will look at your crontab, and if it is time to run, poof, it runs! But every 45 minutes is an interval that will always hit at a 15 minute mark on the clock face. for example starting from zero the first is 0:45. Next will be 90 minutes from zero, or 1:30, the next will be 2:15... so easily you can see that the time for each instance you want to execute your script the minute hand will be on 12, 3, 6, or 9. If you execute your script every 15 minutes, and check the hour to see if it is the correct one, you can then execute your script. You will probably use either a table, or you might also use the modulo feature. Cheers!

Repartition of cron

(I apologize in advance for bad formulation of my problem, please consider english is not my first language).
I have several processes (crons) and I want to "optimize" the schedule when to launch them.
For example, cron c1 starts every 3 minutes, cron c1 starts every 7 minutes and cron c3 starts every 18 minutes. Assume they last only a few seconds before stopping.
The unit of time here is 1 minute.
Now, what I want is that these crons are distributed so that we don't have a moment where many of them start and then long time interval with no cron at all. For example, if c1 and c3 both start at time 0, then they will start again together every 18 minutes. It would be better to start cron c1 at time 0 and then c3 at time 1, so that they are never launched together.
So the idea is, given a list of crons with periodicity, to plan a schedule, so that there is as much time between each cron as possible and as few as possible moments when two crons start together.
Are there some well-known algorithms about such problems?
The real-life application of this problem is: ~ 200 crons. Some of them are launched every 5 or ~10 or ~30 minutes and last very short (few seconds), some (~20 - 25) are launched every 2 hours and last a few minutes. So the idea is also that the big crons are not launched at the same time.
I am a mathematician myself and not a computer scientist, so I asked this question on https://math.stackexchange.com/, since I consider this being a "nice" question for mathematicians too.
I think you should consider the ressources used by each of your crons and then schedule your jobs from that.
I don't think there is a particular algorithm for that.

Perl Cron Scheduler: start at x time, execute every y minutes forever

I'm using perl cron, and I want to make a rule like this
run every xx min/hours starting at yy:yy time (until the end of time)
How would I put this into a cron string? perl:cron seems to use the same syntax as regular cron so a regular cron string should work
TIA!
The short answer is that you will either need to write this yourself or find a different third-party package, due to your requirements. There's two things you're asking for that cron doesn't do:
Run every X minutes.
Say you want to run every 40 minutes, and you write this */40 * * * *. This actually runs every 60 minutes at 1:40, 2:40, etc.
Start/Stop at time Y/Z.
There's simply no cron syntax for this. You could use a couple more cronjobs to add/remove the main cronjob at the specified times, but this smells a lot like self-modifying code. Given the complexity (read: unreliability), it's probably better to find a different system.
You can specify intervals with a slash. Here's every 5 minutes:
*/5 * * * *
This is every 2 hours:
0 */2 * * *
You cannot give a start/ end time in cron.

Resources