How to Run Cronjobs More Often Than Once Per Minute

How to run Cronjobs more often than once per minute?

For starters, I'd recommend using the command line version of PHP rather than using curl to call a script. You can then create a PHP script with a sensible lifetime that isn't constrained by having to output a response within a given time period.

As such, you can then simply sleep/check for emails/transmit/sleep, etc. within the PHP script rather than needlessly using cron.

Additionally, I'd take care to ensure that multiple PHP scripts aren't operating on the database table at the same time, either by using a pid file or database setting approach (if a given file/setting exists/is set, abort processing) or by sensibly timing the cron job and limiting the maximum processing time of the script by checking how long it's been running for prior to beginning the "check for emails" portion of the cycle.

Running a cron every 30 seconds

You have */30 in the minutes specifier - that means every minute but with a step of 30 (in other words, every half hour). Since cron does not go down to sub-minute resolutions, you will need to find another way.

One possibility, though it's a bit of a kludge(a), is to have two jobs, one offset by 30 seconds:

# Need these to run on 30-sec boundaries, keep commands in sync.
* * * * * /path/to/executable param1 param2
* * * * * ( sleep 30 ; /path/to/executable param1 param2 )

You'll see I've added comments and formatted to ensure it's easy to keep them synchronised.

Both cron jobs actually run every minute but the latter one will wait half a minute before executing the "meat" of the job, /path/to/executable.

For other (non-cron-based) options, see the other answers here, particularly the ones mentioning fcron and systemd. These are probably preferable assuming your system has the ability to use them (such as installing fcron or having a distro with systemd in it).


If you don't want to use the kludgy solution, you can use a loop-based solution with a small modification. You'll still have to manage keeping your process running in some form but, once that's sorted, the following script should work:

#!/bin/env bash

# Debug code to start on minute boundary and to
# gradually increase maximum payload duration to
# see what happens when the payload exceeds 30 seconds.

((maxtime = 20))
while [[ "$(date +%S)" != "00" ]]; do true; done

while true; do
# Start a background timer BEFORE the payload runs.

sleep 30 &

# Execute the payload, some random duration up to the limit.
# Extra blank line if excess payload.

((delay = RANDOM % maxtime + 1))
((maxtime += 1))
echo "$(date) Sleeping for ${delay} seconds (max ${maxtime})."
[[ ${delay} -gt 30 ]] && echo
sleep ${delay}

# Wait for timer to finish before next cycle.

wait
done

The trick is to use a sleep 30 but to start it in the background before your payload runs. Then, after the payload is finished, just wait for the background sleep to finish.

If the payload takes n seconds (where n <= 30), the wait after the payload will then be 30 - n seconds. If it takes more than 30 seconds, then the next cycle will be delayed until the payload is finished, but no longer.

You'll see that I have debug code in there to start on a one-minute boundary to make the output initially easier to follow. I also gradually increase the maximum payload time so you'll eventually see the payload exceed the 30-second cycle time (an extra blank line is output so the effect is obvious).

A sample run follows (where cycles normally start 30 seconds after the previous cycle):

Tue May 26 20:56:00 AWST 2020 Sleeping for 9 seconds (max 21).
Tue May 26 20:56:30 AWST 2020 Sleeping for 19 seconds (max 22).
Tue May 26 20:57:00 AWST 2020 Sleeping for 9 seconds (max 23).
Tue May 26 20:57:30 AWST 2020 Sleeping for 7 seconds (max 24).
Tue May 26 20:58:00 AWST 2020 Sleeping for 2 seconds (max 25).
Tue May 26 20:58:30 AWST 2020 Sleeping for 8 seconds (max 26).
Tue May 26 20:59:00 AWST 2020 Sleeping for 20 seconds (max 27).
Tue May 26 20:59:30 AWST 2020 Sleeping for 25 seconds (max 28).
Tue May 26 21:00:00 AWST 2020 Sleeping for 5 seconds (max 29).
Tue May 26 21:00:30 AWST 2020 Sleeping for 6 seconds (max 30).
Tue May 26 21:01:00 AWST 2020 Sleeping for 27 seconds (max 31).
Tue May 26 21:01:30 AWST 2020 Sleeping for 25 seconds (max 32).
Tue May 26 21:02:00 AWST 2020 Sleeping for 15 seconds (max 33).
Tue May 26 21:02:30 AWST 2020 Sleeping for 10 seconds (max 34).
Tue May 26 21:03:00 AWST 2020 Sleeping for 5 seconds (max 35).
Tue May 26 21:03:30 AWST 2020 Sleeping for 35 seconds (max 36).

Tue May 26 21:04:05 AWST 2020 Sleeping for 2 seconds (max 37).
Tue May 26 21:04:35 AWST 2020 Sleeping for 20 seconds (max 38).
Tue May 26 21:05:05 AWST 2020 Sleeping for 22 seconds (max 39).
Tue May 26 21:05:35 AWST 2020 Sleeping for 18 seconds (max 40).
Tue May 26 21:06:05 AWST 2020 Sleeping for 33 seconds (max 41).

Tue May 26 21:06:38 AWST 2020 Sleeping for 31 seconds (max 42).

Tue May 26 21:07:09 AWST 2020 Sleeping for 6 seconds (max 43).

If you want to avoid the kludgy solution, this is probably better. You'll still need a cron job (or equivalent) to periodically detect if this script is running and, if not, start it. But the script itself then handles the timing.


(a) Some of my workmates would say that kludges are my specialty :-)

Google App Engine cron with more than 1 minute frequency

You can fire a task using the Task Queue API that schedules another task using an eta < now + 1min.

Running cron less then one minute- laravel

You can not execute cron jobs with less than one minute interval.
You can check alternate solutions on
https://serverfault.com/questions/49082/can-i-run-a-cron-job-more-frequently-than-every-minute

setting Cronjobs in exact time

Your script will run at 21:50 every day.

See the file formats manpage for crontab:

$ man 5 crontab

The line parts before the command for your crontab are: (Below is from the manpage.)

The time and date fields are:

field allowed values
----- --------------
minute 0-59
hour 0-23
day of month 1-31
month 1-12 (or names, see below)
day of week 0-7 (0 or 7 is Sun, or use names)

A field may be an asterisk (*), which always stands for "first-last".

And you will see this example even further below: (Below is also from the manpage.)

# run five minutes after midnight, every day
5 0 * * * $HOME/bin/daily.job >> $HOME/tmp/out 2>&1

man is your friend.

Run Cron job every N minutes plus offset

To run a task every 20 minutes starting at 5 past the hour, try this:

 5-59/20 * * * *

Explanation

An * in the minute field is the same as 0-59/1 where 0-59 is the range and 1 is the step. The command will run at the first minute in the range (0), then at all successive minutes that are distant from the first by step (1), until the last (59).

Which is why */20 * * * * will run at 0 minutes, 20 minutes after, and 40 minutes after -- which is the same as every 20 minutes. However, */25 * * * * will run at 0 minutes, 25 minutes after, and 50 minutes after -- which is not the same as every 25 minutes. That's why it's usually desirable to use a step value in the minute field that divides evenly into 60.

So to offset the start time, specify the range explicitly and set the first value to the amount of the offset.

Examples

5-59/20 * * * * will run at 5 minutes after, 25 minutes after, and 45 minutes after.

10-59/25 * * * * will run at 10 minutes after and 35 minutes after.

1-59/2 * * * * will run every odd minute.



Related Topics



Leave a reply



Submit